<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;
use chrono::NaiveDateTime;
use chrono::Local;
use chrono::NaiveDate;

use error::HabitError as HE;
use error::HabitErrorKind as HEK;
use error::*;
use iter::HabitInstanceStoreIdIterator;
use util::date_to_string;
use util::date_from_string;

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Entry;
use libimagstore::iter::get::StoreIdGetIteratorExtension;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

/// A HabitTemplate is a "template" of a habit. A user may define a habit "Eat vegetable".
/// If the user ate a vegetable, she should create a HabitInstance from the Habit with the
/// appropriate date (and optionally a comment) set.
pub trait HabitTemplate : Sized {

    /// Create an instance from this habit template
    ///
    /// By default creates an instance with the name of the template, the current time and the
    /// current date and copies the comment from the template to the instance.
    ///
    /// It uses `Store::retrieve()` underneath
    fn create_instance<'a>(&self, store: &'a Store) -> Result<FileLockEntry<'a>>;

    /// Check whether the instance is a habit by checking its headers for the habit data
    fn is_habit_template(&self) -> Result<bool>;

    fn habit_name(&self) -> Result<String>;
    fn habit_basedate(&self) -> Result<String>;
    fn habit_recur_spec(&self) -> Result<String>;
    fn habit_comment(&self) -> Result<String>;

    /// Create a StoreId for a habit name and a date the habit should be instantiated for
    fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId>;
}

impl HabitTemplate for Entry {

    fn create_instance<'a>(&self, store: &'a Store) -> Result<FileLockEntry<'a>> {
        let name    = self.habit_name()?;
        let comment = self.habit_comment()?;
        let date    = date_to_string(&Local::today().naive_local());
        let id      = instance_id_for_name_and_datestr(&name, &date)?;

        store.retrieve(id)
            .map_err(From::from)
            .and_then(|mut entry| {
                {
                    let mut hdr = entry.get_header_mut();
                    try!(hdr.insert("habit.instance.name",    Value::String(name)));
                    try!(hdr.insert("habit.instance.date",    Value::String(date)));
                    try!(hdr.insert("habit.instance.comment", Value::String(comment)));
                }
                Ok(entry)
            })
    }

    /// Check whether the instance is a habit by checking its headers for the habit data
    fn is_habit_template(&self) -> Result<bool> {
        [
            "habit.template.name",
            "habit.template.basedate",
            "habit.template.comment",
        ].iter().fold(Ok(true), |acc, path| acc.and_then(|b| {
            self.get_header()
                .read(path)
                .map(|o| is_match!(o, Some(&Value::String(_))))
                .map_err(From::from)
        }))
    }

    fn habit_name(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.name")
    }

    fn habit_basedate(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.basedate")
    }

    fn habit_recur_spec(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.recurspec")
    }

    fn habit_comment(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.comment")
    }

    fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId> {
        instance_id_for_name_and_datestr(habit_name, &date_to_string(habit_date))
    }

}

fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) -> Result<StoreId> {
    use module_path::ModuleEntryPath;

    ModuleEntryPath::new(format!("instance/{}-{}", habit_name, habit_date))
        .into_storeid()
        .map_err(HE::from)
}

#[inline]
fn get_string_header_from_habit(e: &Entry, path: &'static str) -> Result<String> {
    match e.get_header().read(path)? {
        Some(&Value::String(ref s)) => Ok(s.clone()),
        Some(_) => Err(HEK::HeaderTypeError(path, "String").into()),
        None    => Err(HEK::HeaderFieldMissing(path).into()),
    }
}

pub mod builder {
    use toml::Value;
    use toml_query::insert::TomlValueInsertExt;
    use chrono::NaiveDate;

    use libimagstore::store::Store;
    use libimagstore::storeid::StoreId;
    use libimagstore::storeid::IntoStoreId;
    use libimagstore::store::FileLockEntry;

    use error::HabitError as HE;
    use error::HabitErrorKind as HEK;
    use error::*;
    use util::date_to_string;
    use util::date_from_string;

    pub struct HabitBuilder {
        name: Option<String>,
        comment: Option<String>,
        basedate: Option<NaiveDate>,
        recurspec: Option<String>,
    }

    impl HabitBuilder {

        pub fn with_name(mut self, name: String) -> Self {
            self.name = Some(name);
            self
        }

        pub fn with_comment(mut self, comment: String) -> Self {
            self.comment = Some(comment);
            self
        }

        pub fn with_basedate(mut self, date: NaiveDate) -> Self {
            self.basedate = Some(date);
            self
        }

        pub fn with_recurspec(mut self, spec: String) -> Self {
            self.recurspec = Some(spec);
            self
        }

        pub fn build<'a>(self, store: &'a Store) -> Result<FileLockEntry<'a>> {
            #[inline]
            fn mkerr(s: &'static str) -> HE {
                HE::from_kind(HEK::HabitBuilderMissing(s))
            }

            let name      = try!(self.name.ok_or_else(|| mkerr("name")));
            let dateobj   = try!(self.basedate.ok_or_else(|| mkerr("date")));
            let recur     = try!(self.recurspec.ok_or_else(|| mkerr("recurspec")));
            if let Err(e) = ::kairos::parser::parse(&recur) {
                return Err(e).map_err(From::from);
            }
            let date      = date_to_string(&dateobj);
            let comment   = self.comment.unwrap_or_else(|| String::new());
            let sid       = try!(build_habit_template_sid(&name));
            let mut entry = try!(store.create(sid));

            try!(entry.get_header_mut().insert("habit.template.name", Value::String(name)));
            try!(entry.get_header_mut().insert("habit.template.basedate", Value::String(date)));
            try!(entry.get_header_mut().insert("habit.template.recurspec", Value::String(recur)));
            try!(entry.get_header_mut().insert("habit.template.comment", Value::String(comment)));

            Ok(entry)
        }

    }

    impl Default for HabitBuilder {
        fn default() -> Self {
            HabitBuilder {
                name: None,
                comment: None,
                basedate: None,
                recurspec: None,
            }
        }
    }

    /// Buld a StoreId for a Habit from a date object and a name of a habit
    fn build_habit_template_sid(name: &String) -> Result<StoreId> {
        use module_path::ModuleEntryPath;
        ModuleEntryPath::new(format!("template/{}", name)).into_storeid().map_err(From::from)
    }

}

<commit_msg>Add debugging output<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;
use toml_query::read::TomlValueReadExt;
use toml_query::insert::TomlValueInsertExt;
use chrono::NaiveDateTime;
use chrono::Local;
use chrono::NaiveDate;

use error::HabitError as HE;
use error::HabitErrorKind as HEK;
use error::*;
use iter::HabitInstanceStoreIdIterator;
use util::date_to_string;
use util::date_from_string;

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Entry;
use libimagstore::iter::get::StoreIdGetIteratorExtension;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

/// A HabitTemplate is a "template" of a habit. A user may define a habit "Eat vegetable".
/// If the user ate a vegetable, she should create a HabitInstance from the Habit with the
/// appropriate date (and optionally a comment) set.
pub trait HabitTemplate : Sized {

    /// Create an instance from this habit template
    ///
    /// By default creates an instance with the name of the template, the current time and the
    /// current date and copies the comment from the template to the instance.
    ///
    /// It uses `Store::retrieve()` underneath
    fn create_instance<'a>(&self, store: &'a Store) -> Result<FileLockEntry<'a>>;

    /// Check whether the instance is a habit by checking its headers for the habit data
    fn is_habit_template(&self) -> Result<bool>;

    fn habit_name(&self) -> Result<String>;
    fn habit_basedate(&self) -> Result<String>;
    fn habit_recur_spec(&self) -> Result<String>;
    fn habit_comment(&self) -> Result<String>;

    /// Create a StoreId for a habit name and a date the habit should be instantiated for
    fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId>;
}

impl HabitTemplate for Entry {

    fn create_instance<'a>(&self, store: &'a Store) -> Result<FileLockEntry<'a>> {
        let name    = self.habit_name()?;
        let comment = self.habit_comment()?;
        let date    = date_to_string(&Local::today().naive_local());
        let id      = instance_id_for_name_and_datestr(&name, &date)?;

        store.retrieve(id)
            .map_err(From::from)
            .and_then(|mut entry| {
                {
                    let mut hdr = entry.get_header_mut();
                    try!(hdr.insert("habit.instance.name",    Value::String(name)));
                    try!(hdr.insert("habit.instance.date",    Value::String(date)));
                    try!(hdr.insert("habit.instance.comment", Value::String(comment)));
                }
                Ok(entry)
            })
    }

    /// Check whether the instance is a habit by checking its headers for the habit data
    fn is_habit_template(&self) -> Result<bool> {
        [
            "habit.template.name",
            "habit.template.basedate",
            "habit.template.comment",
        ].iter().fold(Ok(true), |acc, path| acc.and_then(|b| {
            self.get_header()
                .read(path)
                .map(|o| is_match!(o, Some(&Value::String(_))))
                .map_err(From::from)
        }))
    }

    fn habit_name(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.name")
    }

    fn habit_basedate(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.basedate")
    }

    fn habit_recur_spec(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.recurspec")
    }

    fn habit_comment(&self) -> Result<String> {
        get_string_header_from_habit(self, "habit.template.comment")
    }

    fn instance_id_for(habit_name: &String, habit_date: &NaiveDate) -> Result<StoreId> {
        instance_id_for_name_and_datestr(habit_name, &date_to_string(habit_date))
    }

}

fn instance_id_for_name_and_datestr(habit_name: &String, habit_date: &String) -> Result<StoreId> {
    use module_path::ModuleEntryPath;

    ModuleEntryPath::new(format!("instance/{}-{}", habit_name, habit_date))
        .into_storeid()
        .map_err(HE::from)
}

#[inline]
fn get_string_header_from_habit(e: &Entry, path: &'static str) -> Result<String> {
    match e.get_header().read(path)? {
        Some(&Value::String(ref s)) => Ok(s.clone()),
        Some(_) => Err(HEK::HeaderTypeError(path, "String").into()),
        None    => Err(HEK::HeaderFieldMissing(path).into()),
    }
}

pub mod builder {
    use toml::Value;
    use toml_query::insert::TomlValueInsertExt;
    use chrono::NaiveDate;

    use libimagstore::store::Store;
    use libimagstore::storeid::StoreId;
    use libimagstore::storeid::IntoStoreId;
    use libimagstore::store::FileLockEntry;

    use error::HabitError as HE;
    use error::HabitErrorKind as HEK;
    use error::*;
    use util::date_to_string;
    use util::date_from_string;

    pub struct HabitBuilder {
        name: Option<String>,
        comment: Option<String>,
        basedate: Option<NaiveDate>,
        recurspec: Option<String>,
    }

    impl HabitBuilder {

        pub fn with_name(mut self, name: String) -> Self {
            self.name = Some(name);
            self
        }

        pub fn with_comment(mut self, comment: String) -> Self {
            self.comment = Some(comment);
            self
        }

        pub fn with_basedate(mut self, date: NaiveDate) -> Self {
            self.basedate = Some(date);
            self
        }

        pub fn with_recurspec(mut self, spec: String) -> Self {
            self.recurspec = Some(spec);
            self
        }

        pub fn build<'a>(self, store: &'a Store) -> Result<FileLockEntry<'a>> {
            #[inline]
            fn mkerr(s: &'static str) -> HE {
                HE::from_kind(HEK::HabitBuilderMissing(s))
            }

            let name      = try!(self.name.ok_or_else(|| mkerr("name")));
            debug!("Success: Name present");

            let dateobj   = try!(self.basedate.ok_or_else(|| mkerr("date")));
            debug!("Success: Date present");

            let recur     = try!(self.recurspec.ok_or_else(|| mkerr("recurspec")));
            debug!("Success: Recurr spec present");

            if let Err(e) = ::kairos::parser::parse(&recur) {
                return Err(e).map_err(From::from);
            }
            let date      = date_to_string(&dateobj);
            debug!("Success: Date valid");

            let comment   = self.comment.unwrap_or_else(|| String::new());
            let sid       = try!(build_habit_template_sid(&name));

            debug!("Creating entry in store for: {:?}", sid);
            let mut entry = try!(store.create(sid));

            try!(entry.get_header_mut().insert("habit.template.name", Value::String(name)));
            try!(entry.get_header_mut().insert("habit.template.basedate", Value::String(date)));
            try!(entry.get_header_mut().insert("habit.template.recurspec", Value::String(recur)));
            try!(entry.get_header_mut().insert("habit.template.comment", Value::String(comment)));

            debug!("Success: Created entry in store and set headers");
            Ok(entry)
        }

    }

    impl Default for HabitBuilder {
        fn default() -> Self {
            HabitBuilder {
                name: None,
                comment: None,
                basedate: None,
                recurspec: None,
            }
        }
    }

    /// Buld a StoreId for a Habit from a date object and a name of a habit
    fn build_habit_template_sid(name: &String) -> Result<StoreId> {
        use module_path::ModuleEntryPath;
        ModuleEntryPath::new(format!("template/{}", name)).into_storeid().map_err(From::from)
    }

}

<|endoftext|>


<commit_before>//! This module provides a Beckmann microfacet distribution with a
//! Smith shadowing-masking term

use std::f32;

use bxdf;
use linalg::{self, Vector};
use bxdf::microfacet::MicrofacetDistribution;

/// Beckmann microfacet distribution with Smith shadowing-masking. This is the
/// microfacet model described by [Walter et al.](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
pub struct Beckmann {
    width: f32,
}

impl Beckmann {
    /// Create a new Beckmann distribution with the desired width
    pub fn new(w: f32) -> Beckmann {
        // From pbrt-v3, conversion from Blinn-Phong style roughness to approximately
        // equivalent Beckmann alpha
        let roughness = f32::max(w, 0.000001);
        Beckmann { width: roughness }
    }
}

impl MicrofacetDistribution for Beckmann {
    fn normal_distribution(&self, w_h: &Vector) -> f32 {
        if bxdf::cos_theta(w_h) > 0.0 {
            let e = f32::exp(-f32::powf(bxdf::tan_theta(&w_h) / self.width, 2.0));
            e / (f32::consts::PI * f32::powf(self.width, 2.0) * f32::powf(bxdf::cos_theta(&w_h), 4.0))
        } else {
            0.0
        }
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> Vector {
        let log_sample = match f32::ln(1.0 - samples.0) {
            x if f32::is_infinite(x) => 0.0,
            x => x,
        };
        let tan_theta_sqr = -f32::powf(self.width, 2.0) * log_sample;
        let phi = 2.0 * f32::consts::PI * samples.1;
        let cos_theta = 1.0 / f32::sqrt(1.0 + tan_theta_sqr);
        let sin_theta = f32::sqrt(f32::max(0.0, 1.0 - cos_theta * cos_theta));
        let w_h = linalg::spherical_dir(sin_theta, cos_theta, phi);
        // TODO: Can move this check to callers, then we can have microfacet transmission
        if !bxdf::same_hemisphere(w_o, &w_h) {
            -w_h
        } else {
            w_h
        }
    }
    fn pdf(&self, w_h: &Vector) -> f32 {
        f32::abs(bxdf::cos_theta(w_h)) * self.normal_distribution(w_h)
    }
    fn shadowing_masking(&self, w_i: &Vector, w_o: &Vector, w_h: &Vector) -> f32 {
        self.monodir_shadowing(w_i, w_h) * self.monodir_shadowing(w_o, w_h)
    }
    /// Monodirectional shadowing function from Walter et al., we use the Smith
    /// shadowing-masking which uses the reciprocity of this function.
    /// `w` is the incident/outgoing light direction and `w_h` is the microfacet normal
    fn monodir_shadowing(&self, v: &Vector, w_h: &Vector) -> f32 {
        if linalg::dot(v, w_h) / bxdf::cos_theta(v) > 0.0 {
            let a = 1.0 / (self.width * bxdf::tan_theta(v));
            if a < 1.6 {
                let a_sqr = f32::powf(a, 2.0);
                (3.535 * a + 2.181 * a_sqr) / (1.0 + 2.276 * a + 2.577 * a_sqr)
            } else {
                1.0
            }
        } else {
            0.0
        }
    }
}

<commit_msg>Remove stray comment<commit_after>//! This module provides a Beckmann microfacet distribution with a
//! Smith shadowing-masking term

use std::f32;

use bxdf;
use linalg::{self, Vector};
use bxdf::microfacet::MicrofacetDistribution;

/// Beckmann microfacet distribution with Smith shadowing-masking. This is the
/// microfacet model described by [Walter et al.](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
pub struct Beckmann {
    width: f32,
}

impl Beckmann {
    /// Create a new Beckmann distribution with the desired width
    pub fn new(w: f32) -> Beckmann {
        let roughness = f32::max(w, 0.000001);
        Beckmann { width: roughness }
    }
}

impl MicrofacetDistribution for Beckmann {
    fn normal_distribution(&self, w_h: &Vector) -> f32 {
        if bxdf::cos_theta(w_h) > 0.0 {
            let e = f32::exp(-f32::powf(bxdf::tan_theta(&w_h) / self.width, 2.0));
            e / (f32::consts::PI * f32::powf(self.width, 2.0) * f32::powf(bxdf::cos_theta(&w_h), 4.0))
        } else {
            0.0
        }
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> Vector {
        let log_sample = match f32::ln(1.0 - samples.0) {
            x if f32::is_infinite(x) => 0.0,
            x => x,
        };
        let tan_theta_sqr = -f32::powf(self.width, 2.0) * log_sample;
        let phi = 2.0 * f32::consts::PI * samples.1;
        let cos_theta = 1.0 / f32::sqrt(1.0 + tan_theta_sqr);
        let sin_theta = f32::sqrt(f32::max(0.0, 1.0 - cos_theta * cos_theta));
        let w_h = linalg::spherical_dir(sin_theta, cos_theta, phi);
        // TODO: Can move this check to callers, then we can have microfacet transmission
        if !bxdf::same_hemisphere(w_o, &w_h) {
            -w_h
        } else {
            w_h
        }
    }
    fn pdf(&self, w_h: &Vector) -> f32 {
        f32::abs(bxdf::cos_theta(w_h)) * self.normal_distribution(w_h)
    }
    fn shadowing_masking(&self, w_i: &Vector, w_o: &Vector, w_h: &Vector) -> f32 {
        self.monodir_shadowing(w_i, w_h) * self.monodir_shadowing(w_o, w_h)
    }
    /// Monodirectional shadowing function from Walter et al., we use the Smith
    /// shadowing-masking which uses the reciprocity of this function.
    /// `w` is the incident/outgoing light direction and `w_h` is the microfacet normal
    fn monodir_shadowing(&self, v: &Vector, w_h: &Vector) -> f32 {
        if linalg::dot(v, w_h) / bxdf::cos_theta(v) > 0.0 {
            let a = 1.0 / (self.width * bxdf::tan_theta(v));
            if a < 1.6 {
                let a_sqr = f32::powf(a, 2.0);
                (3.535 * a + 2.181 * a_sqr) / (1.0 + 2.276 * a + 2.577 * a_sqr)
            } else {
                1.0
            }
        } else {
            0.0
        }
    }
}

<|endoftext|>


<commit_before>pub fn rotate(text: &str, shift_key: u8) -> String {
    text.chars()
        .map(|c| {
            let case = if c.is_uppercase() { 'A' } else { 'a' } as u8;
            if c.is_alphabetic() {
                (((c as u8 - case + shift_key) % 26) + case) as char
            } else {
                c
            }
        })
        .collect::<String>()
}
<commit_msg>rotational-cipher: Updated the example solution to handle the negative shift key tests<commit_after>pub fn rotate(text: &str, key: i8) -> String {
    let key = if key < 0 { (26 + key) as u8 } else { key as u8 };

    text.chars()
        .map(|c| {
            if c.is_alphabetic() {
                let case = if c.is_uppercase() { 'A' } else { 'a' } as u8;

                (((c as u8 - case + key) % 26) + case) as char
            } else {
                c
            }
        })
        .collect()
}
<|endoftext|>


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

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};
use std::fmt;

pub struct Au(i32);

// We don't use #[deriving] here for inlining.
impl Clone for Au {
    #[inline]
    fn clone(&self) -> Au {
        Au(**self)
    }
}

impl fmt::Default for Au {
    fn fmt(obj: &Au, f: &mut fmt::Formatter) {
        write!(f.buf, "Au({})", *obj);
    }
}

impl Eq for Au {
    #[inline]
    fn eq(&self, other: &Au) -> bool {
        **self == **other
    }
    #[inline]
    fn ne(&self, other: &Au) -> bool {
        **self != **other
    }
}

impl Add<Au,Au> for Au {
    #[inline]
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    #[inline]
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    #[inline]
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    #[inline]
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    #[inline]
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    #[inline]
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    #[inline]
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    #[inline]
    fn le(&self, other: &Au) -> bool { **self <= **other }
    #[inline]
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    #[inline]
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    #[inline]
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au { Au(0) }
    #[inline]
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

#[inline]
pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
#[inline]
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:ToPrimitive>(n: T) -> Option<Au> {
        Some(Au(n.to_i32().unwrap()))
    }
}

impl ToPrimitive for Au {
    fn to_i64(&self) -> Option<i64> {
        Some(**self as i64)
    }

    fn to_u64(&self) -> Option<u64> {
        Some(**self as u64)
    }

    fn to_f32(&self) -> Option<f32> {
        (**self).to_f32()
    }

    fn to_f64(&self) -> Option<f64> {
        (**self).to_f64()
    }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f64) -> Au {
        Au(((*self as f64) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60).unwrap()
    }

    #[inline]
    pub fn to_nearest_px(&self) -> int {
        ((**self as f64) / 60f64).round() as int
    }

    #[inline]
    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    #[inline]
    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    #[inline]
    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    #[inline]
    pub fn from_frac_px(px: f64) -> Au {
        Au((px * 60f64) as i32)
    }

    #[inline]
    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    #[inline]
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72f64 * 96f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96f64 * 72f64
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: f64) -> Au {
    Au((px * 60f64) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60).unwrap()
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> f64 {
    (*au as f64) / 60f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: f64) -> Au {
    from_px((pt / 72f64 * 96f64) as int)
}

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

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};
use std::fmt;

pub struct Au(i32);

// We don't use #[deriving] here for inlining.
impl Clone for Au {
    #[inline]
    fn clone(&self) -> Au {
        Au(**self)
    }
}

impl fmt::Default for Au {
    fn fmt(obj: &Au, f: &mut fmt::Formatter) {
        let Au(n) = *obj;
        write!(f.buf, "Au({})", n);
    }
}

impl Eq for Au {
    #[inline]
    fn eq(&self, other: &Au) -> bool {
        **self == **other
    }
    #[inline]
    fn ne(&self, other: &Au) -> bool {
        **self != **other
    }
}

impl Add<Au,Au> for Au {
    #[inline]
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    #[inline]
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    #[inline]
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    #[inline]
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    #[inline]
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    #[inline]
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    #[inline]
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    #[inline]
    fn le(&self, other: &Au) -> bool { **self <= **other }
    #[inline]
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    #[inline]
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    #[inline]
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au { Au(0) }
    #[inline]
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

#[inline]
pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
#[inline]
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:ToPrimitive>(n: T) -> Option<Au> {
        Some(Au(n.to_i32().unwrap()))
    }
}

impl ToPrimitive for Au {
    fn to_i64(&self) -> Option<i64> {
        Some(**self as i64)
    }

    fn to_u64(&self) -> Option<u64> {
        Some(**self as u64)
    }

    fn to_f32(&self) -> Option<f32> {
        (**self).to_f32()
    }

    fn to_f64(&self) -> Option<f64> {
        (**self).to_f64()
    }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f64) -> Au {
        Au(((*self as f64) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60).unwrap()
    }

    #[inline]
    pub fn to_nearest_px(&self) -> int {
        ((**self as f64) / 60f64).round() as int
    }

    #[inline]
    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    #[inline]
    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    #[inline]
    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    #[inline]
    pub fn from_frac_px(px: f64) -> Au {
        Au((px * 60f64) as i32)
    }

    #[inline]
    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    #[inline]
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72f64 * 96f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96f64 * 72f64
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: f64) -> Au {
    Au((px * 60f64) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60).unwrap()
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> f64 {
    (*au as f64) / 60f64
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: f64) -> Au {
    from_px((pt / 72f64 * 96f64) as int)
}

<|endoftext|>


<commit_before>use compositor::{Server, Shell, View};
use wlroots::{CompositorHandle, XdgV6ShellHandler, XdgV6ShellManagerHandler, XdgV6ShellState::*,
              XdgV6ShellSurfaceHandle};

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct XdgV6 {
    shell_surface: XdgV6ShellSurfaceHandle
}

impl XdgV6 {
    pub fn new() -> Self {
        XdgV6 { ..XdgV6::default() }
    }
}

impl XdgV6ShellHandler for XdgV6 {}

pub struct XdgV6ShellManager;

impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: CompositorHandle,
                   mut shell_surface: XdgV6ShellSurfaceHandle)
                   -> Option<Box<XdgV6ShellHandler>> {
        let is_toplevel = with_handles!([(shell_surface: {&mut shell_surface})] => {
            match shell_surface.state().unwrap() {
                TopLevel(_) => true,
                _ => false
            }
        }).unwrap();

        if is_toplevel {
            with_handles!([(compositor: {compositor})] => {
                let server: &mut Server = compositor.into();
                server.views
                    .push(View::new(Shell::XdgV6(shell_surface.into())));
            }).unwrap();
        }

        Some(Box::new(XdgV6::new()))
    }

    fn surface_destroyed(&mut self,
                         compositor: CompositorHandle,
                         shell_surface: XdgV6ShellSurfaceHandle) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut Server = compositor.into();
            let destroyed_shell = shell_surface.into();
            if let Some(pos) = server.views
                .iter()
                .position(|view| view.shell == destroyed_shell)
            {
                server.views.remove(pos);
            }

            let focused = if let Some(ref focused) = server.seat.focused {
                focused.shell == destroyed_shell
            } else {
                false
            };

            if focused {
                server.seat.focused = None;
            }
        }).unwrap();
    }
}
<commit_msg>remove seat focus in a rustic way<commit_after>use compositor::{Server, Shell, View};
use wlroots::{CompositorHandle, XdgV6ShellHandler, XdgV6ShellManagerHandler, XdgV6ShellState::*,
              XdgV6ShellSurfaceHandle};

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct XdgV6 {
    shell_surface: XdgV6ShellSurfaceHandle
}

impl XdgV6 {
    pub fn new() -> Self {
        XdgV6 { ..XdgV6::default() }
    }
}

impl XdgV6ShellHandler for XdgV6 {}

pub struct XdgV6ShellManager;

impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: CompositorHandle,
                   mut shell_surface: XdgV6ShellSurfaceHandle)
                   -> Option<Box<XdgV6ShellHandler>> {
        let is_toplevel = with_handles!([(shell_surface: {&mut shell_surface})] => {
            match shell_surface.state().unwrap() {
                TopLevel(_) => true,
                _ => false
            }
        }).unwrap();

        if is_toplevel {
            with_handles!([(compositor: {compositor})] => {
                let server: &mut Server = compositor.into();
                server.views
                    .push(View::new(Shell::XdgV6(shell_surface.into())));
            }).unwrap();
        }

        Some(Box::new(XdgV6::new()))
    }

    fn surface_destroyed(&mut self,
                         compositor: CompositorHandle,
                         shell_surface: XdgV6ShellSurfaceHandle) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut Server = compositor.into();
            let destroyed_shell = shell_surface.into();
            if let Some(pos) = server.views
                .iter()
                .position(|view| view.shell == destroyed_shell)
            {
                server.views.remove(pos);
            }

            server.seat.focused = server.seat.focused.take().and_then(|focused| {
                if focused.shell == destroyed_shell {
                    None
                } else {
                    Some(focused)
                }
            });

        }).unwrap();
    }
}
<|endoftext|>


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

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is unsafe**. It is your responsibility to keep the window
//! alive for at least as long as the surface exists.
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(&instance, hinstance, window).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with `Surface::get_capabilities()`.
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`).
//!
//! Then, you should query the capabilities of the surface with `Surface::get_capabilities()` and
//! choose which values you are going to use. Then, call `Swapchain::new`.
//!
//! TODO: add example here
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `Swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module).
//!  - Call `Swapchain::present` with the same index in order to tell the implementation that you
//!    are finished drawing to the image and that it can queue a command to present the image on
//!    the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain.acquire_next_image(Duration::from_millis(500)).unwrap();
//!     draw(images[index]);
//!     swapchain.present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```no_run
//! # use std::time::Duration;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::swapchain::PresentError;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain>, _) = unsafe { ::std::mem::uninitialized() };
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = unsafe { ::std::mem::uninitialized() };
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let index = match swapchain.acquire_next_image(Duration::from_millis(500)) {
//!         Ok(img) => img,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     match swapchain.present(&queue, index) {
//!         Ok(()) => (),
//!         Err(PresentError::OutOfDate) => { recreate_swapchain = true; },
//!         Err(err) => panic!("{:?}", err),
//!     }
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;
use vk;

pub use self::surface::Capabilities;
pub use self::surface::Surface;
pub use self::surface::PresentMode;
pub use self::surface::SurfaceTransform;
pub use self::surface::CompositeAlpha;
pub use self::surface::ColorSpace;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::Swapchain;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentError;

pub mod display;
mod surface;
mod swapchain;

/// List of supported composite alpha modes.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransforms {
    pub identity: bool,
    pub rotate90: bool,
    pub rotate180: bool,
    pub rotate270: bool,
    pub horizontal_mirror: bool,
    pub horizontal_mirror_rotate90: bool,
    pub horizontal_mirror_rotate180: bool,
    pub horizontal_mirror_rotate270: bool,
    pub inherit: bool,
}

impl SupportedSurfaceTransforms {
    /// Builds a `SupportedSurfaceTransforms` with all fields set to false.
    #[inline]
    pub fn none() -> SupportedSurfaceTransforms {
        SupportedSurfaceTransforms {
            identity: false,
            rotate90: false,
            rotate180: false,
            rotate270: false,
            horizontal_mirror: false,
            horizontal_mirror_rotate90: false,
            horizontal_mirror_rotate180: false,
            horizontal_mirror_rotate270: false,
            inherit: false,
        }
    }

    #[inline]
    fn from_bits(val: vk::SurfaceTransformFlagsKHR) -> SupportedSurfaceTransforms {
        macro_rules! v {
            ($val:expr, $out:ident, $e:expr, $f:ident) => (
                if ($val & $e) != 0 { $out.$f = true; }
            );
        }

        let mut result = SupportedSurfaceTransforms::none();
        v!(val, result, vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, identity);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, rotate90);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, rotate180);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, rotate270);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, horizontal_mirror);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
                        horizontal_mirror_rotate90);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
                        horizontal_mirror_rotate180);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
                        horizontal_mirror_rotate270);
        v!(val, result, vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR, inherit);
        result
    }

    /// Returns true if the given `SurfaceTransform` is in this list.
    #[inline]
    pub fn supports(&self, value: SurfaceTransform) -> bool {
        match value {
            SurfaceTransform::Identity => self.identity,
            SurfaceTransform::Rotate90 => self.rotate90,
            SurfaceTransform::Rotate180 => self.rotate180,
            SurfaceTransform::Rotate270 => self.rotate270,
            SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
            SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
            SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
            SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
            SurfaceTransform::Inherit => self.inherit,
        }
    }

    /// Returns an iterator to the list of supported composite alpha.
    #[inline]
    pub fn iter(&self) -> SupportedSurfaceTransformsIter {
        SupportedSurfaceTransformsIter(self.clone())
    }
}

/// Enumeration of the `SurfaceTransform` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);

impl Iterator for SupportedSurfaceTransformsIter {
    type Item = SurfaceTransform;

    #[inline]
    fn next(&mut self) -> Option<SurfaceTransform> {
        if self.0.identity { self.0.identity = false; return Some(SurfaceTransform::Identity); }
        if self.0.rotate90 { self.0.rotate90 = false; return Some(SurfaceTransform::Rotate90); }
        if self.0.rotate180 { self.0.rotate180 = false; return Some(SurfaceTransform::Rotate180); }
        if self.0.rotate270 { self.0.rotate270 = false; return Some(SurfaceTransform::Rotate270); }
        if self.0.horizontal_mirror { self.0.horizontal_mirror = false; return Some(SurfaceTransform::HorizontalMirror); }
        if self.0.horizontal_mirror_rotate90 { self.0.horizontal_mirror_rotate90 = false; return Some(SurfaceTransform::HorizontalMirrorRotate90); }
        if self.0.horizontal_mirror_rotate180 { self.0.horizontal_mirror_rotate180 = false; return Some(SurfaceTransform::HorizontalMirrorRotate180); }
        if self.0.horizontal_mirror_rotate270 { self.0.horizontal_mirror_rotate270 = false; return Some(SurfaceTransform::HorizontalMirrorRotate270); }
        if self.0.inherit { self.0.inherit = false; return Some(SurfaceTransform::Inherit); }
        None
    }
}

impl Default for SurfaceTransform {
    #[inline]
    fn default() -> SurfaceTransform {
        SurfaceTransform::Identity
    }
}

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<commit_msg>Fix some types not being reexported<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.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is unsafe**. It is your responsibility to keep the window
//! alive for at least as long as the surface exists.
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(&instance, hinstance, window).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with `Surface::get_capabilities()`.
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`).
//!
//! Then, you should query the capabilities of the surface with `Surface::get_capabilities()` and
//! choose which values you are going to use. Then, call `Swapchain::new`.
//!
//! TODO: add example here
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `Swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module).
//!  - Call `Swapchain::present` with the same index in order to tell the implementation that you
//!    are finished drawing to the image and that it can queue a command to present the image on
//!    the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain.acquire_next_image(Duration::from_millis(500)).unwrap();
//!     draw(images[index]);
//!     swapchain.present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```no_run
//! # use std::time::Duration;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::swapchain::PresentError;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain>, _) = unsafe { ::std::mem::uninitialized() };
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = unsafe { ::std::mem::uninitialized() };
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let index = match swapchain.acquire_next_image(Duration::from_millis(500)) {
//!         Ok(img) => img,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     match swapchain.present(&queue, index) {
//!         Ok(()) => (),
//!         Err(PresentError::OutOfDate) => { recreate_swapchain = true; },
//!         Err(err) => panic!("{:?}", err),
//!     }
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;
use vk;

pub use self::surface::Capabilities;
pub use self::surface::Surface;
pub use self::surface::PresentMode;
pub use self::surface::SupportedPresentModes;
pub use self::surface::SupportedPresentModesIter;
pub use self::surface::SurfaceTransform;
pub use self::surface::CompositeAlpha;
pub use self::surface::SupportedCompositeAlpha;
pub use self::surface::SupportedCompositeAlphaIter;
pub use self::surface::ColorSpace;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::Swapchain;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentError;

pub mod display;
mod surface;
mod swapchain;

/// List of supported composite alpha modes.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransforms {
    pub identity: bool,
    pub rotate90: bool,
    pub rotate180: bool,
    pub rotate270: bool,
    pub horizontal_mirror: bool,
    pub horizontal_mirror_rotate90: bool,
    pub horizontal_mirror_rotate180: bool,
    pub horizontal_mirror_rotate270: bool,
    pub inherit: bool,
}

impl SupportedSurfaceTransforms {
    /// Builds a `SupportedSurfaceTransforms` with all fields set to false.
    #[inline]
    pub fn none() -> SupportedSurfaceTransforms {
        SupportedSurfaceTransforms {
            identity: false,
            rotate90: false,
            rotate180: false,
            rotate270: false,
            horizontal_mirror: false,
            horizontal_mirror_rotate90: false,
            horizontal_mirror_rotate180: false,
            horizontal_mirror_rotate270: false,
            inherit: false,
        }
    }

    #[inline]
    fn from_bits(val: vk::SurfaceTransformFlagsKHR) -> SupportedSurfaceTransforms {
        macro_rules! v {
            ($val:expr, $out:ident, $e:expr, $f:ident) => (
                if ($val & $e) != 0 { $out.$f = true; }
            );
        }

        let mut result = SupportedSurfaceTransforms::none();
        v!(val, result, vk::SURFACE_TRANSFORM_IDENTITY_BIT_KHR, identity);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, rotate90);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, rotate180);
        v!(val, result, vk::SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, rotate270);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, horizontal_mirror);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR,
                        horizontal_mirror_rotate90);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR,
                        horizontal_mirror_rotate180);
        v!(val, result, vk::SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR,
                        horizontal_mirror_rotate270);
        v!(val, result, vk::SURFACE_TRANSFORM_INHERIT_BIT_KHR, inherit);
        result
    }

    /// Returns true if the given `SurfaceTransform` is in this list.
    #[inline]
    pub fn supports(&self, value: SurfaceTransform) -> bool {
        match value {
            SurfaceTransform::Identity => self.identity,
            SurfaceTransform::Rotate90 => self.rotate90,
            SurfaceTransform::Rotate180 => self.rotate180,
            SurfaceTransform::Rotate270 => self.rotate270,
            SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
            SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
            SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
            SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
            SurfaceTransform::Inherit => self.inherit,
        }
    }

    /// Returns an iterator to the list of supported composite alpha.
    #[inline]
    pub fn iter(&self) -> SupportedSurfaceTransformsIter {
        SupportedSurfaceTransformsIter(self.clone())
    }
}

/// Enumeration of the `SurfaceTransform` that are supported.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);

impl Iterator for SupportedSurfaceTransformsIter {
    type Item = SurfaceTransform;

    #[inline]
    fn next(&mut self) -> Option<SurfaceTransform> {
        if self.0.identity { self.0.identity = false; return Some(SurfaceTransform::Identity); }
        if self.0.rotate90 { self.0.rotate90 = false; return Some(SurfaceTransform::Rotate90); }
        if self.0.rotate180 { self.0.rotate180 = false; return Some(SurfaceTransform::Rotate180); }
        if self.0.rotate270 { self.0.rotate270 = false; return Some(SurfaceTransform::Rotate270); }
        if self.0.horizontal_mirror { self.0.horizontal_mirror = false; return Some(SurfaceTransform::HorizontalMirror); }
        if self.0.horizontal_mirror_rotate90 { self.0.horizontal_mirror_rotate90 = false; return Some(SurfaceTransform::HorizontalMirrorRotate90); }
        if self.0.horizontal_mirror_rotate180 { self.0.horizontal_mirror_rotate180 = false; return Some(SurfaceTransform::HorizontalMirrorRotate180); }
        if self.0.horizontal_mirror_rotate270 { self.0.horizontal_mirror_rotate270 = false; return Some(SurfaceTransform::HorizontalMirrorRotate270); }
        if self.0.inherit { self.0.inherit = false; return Some(SurfaceTransform::Inherit); }
        None
    }
}

impl Default for SurfaceTransform {
    #[inline]
    fn default() -> SurfaceTransform {
        SurfaceTransform::Identity
    }
}

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<|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.

//! Link between Vulkan and a window and/or the screen.
//!
//! In order to draw on the screen or a window, you have to use two steps:
//!
//! - Create a `Surface` object that represents the location where the image will show up.
//! - Create a `Swapchain` using that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them. However
//! due to double-buffering or other caching mechanism, the rendering will not automatically be
//! shown on screen. In order to show the output on screen, you have to *present* the swapchain
//! by using the method with the same name.
//!
//! # Extensions
//!
//! Theses capabilities depend on some extensions:
//!
//! - `VK_KHR_surface`
//! - `VK_KHR_swapchain`
//! - `VK_KHR_display`
//! - `VK_KHR_display_swapchain`
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!

use std::sync::atomic::AtomicBool;

pub use self::surface::Capabilities;
pub use self::surface::Surface;
pub use self::surface::PresentMode;
pub use self::surface::SurfaceTransform;
pub use self::surface::CompositeAlpha;
pub use self::surface::ColorSpace;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::Swapchain;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentError;

pub mod display;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<commit_msg>Add documentation for swapchains<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.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is unsafe**. It is your responsibility to keep the window
//! alive for at least as long as the surface exists.
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # fn build_window() -> *const u32 { ptr::null() }
//! let window = build_window();
//! let _surface = unsafe { Surface::from_hwnd(&instance, ptr::null(), window).unwrap() };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with `Surface::get_capabilities()`.
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`).
//!
//! Then, you should query the capabilities of the surface with `Surface::get_capabilities()` and
//! choose which values you are going to use. Then, call `Swapchain::new`.
//!
//! TODO: add example here
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `Swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module).
//!  - Call `Swapchain::present` with the same index in order to tell the implementation that you
//!    are finished drawing to the image and that it can queue a command to present the image on
//!    the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain.acquire_next_image(Duration::from_millis(500)).unwrap();
//!     draw(images[index]);
//!     swapchain.present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: add example here
//!

use std::sync::atomic::AtomicBool;

pub use self::surface::Capabilities;
pub use self::surface::Surface;
pub use self::surface::PresentMode;
pub use self::surface::SurfaceTransform;
pub use self::surface::CompositeAlpha;
pub use self::surface::ColorSpace;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::Swapchain;
pub use self::swapchain::AcquireError;
pub use self::swapchain::PresentError;

pub mod display;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<|endoftext|>


<commit_before>#![cfg(target_os = "linux")]

extern crate libc;
extern crate pagecache;
extern crate rand;
extern crate sled;
extern crate tests;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(5000)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<commit_msg>Remove pagecache crate from crash tests<commit_after>#![cfg(target_os = "linux")]

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(5000)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<|endoftext|>