<commit_before>//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).

// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;

use std::fmt::{self, Display};

use self::RenameRule::*;

/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(Copy, Clone, PartialEq)]
pub enum RenameRule {
    /// Don't apply a default rename rule.
    None,
    /// Rename direct children to "lowercase" style.
    LowerCase,
    /// Rename direct children to "UPPERCASE" style.
    UPPERCASE,
    /// Rename direct children to "PascalCase" style, as typically used for
    /// enum variants.
    PascalCase,
    /// Rename direct children to "camelCase" style.
    CamelCase,
    /// Rename direct children to "snake_case" style, as commonly used for
    /// fields.
    SnakeCase,
    /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
    /// used for constants.
    ScreamingSnakeCase,
    /// Rename direct children to "kebab-case" style.
    KebabCase,
    /// Rename direct children to "SCREAMING-KEBAB-CASE" style.
    ScreamingKebabCase,
}

static RENAME_RULES: &[(&str, RenameRule)] = &[
    ("lowercase", LowerCase),
    ("UPPERCASE", UPPERCASE),
    ("PascalCase", PascalCase),
    ("camelCase", CamelCase),
    ("snake_case", SnakeCase),
    ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
    ("kebab-case", KebabCase),
    ("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
];

impl RenameRule {
    pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
        for (name, rule) in RENAME_RULES {
            if rename_all_str == *name {
                return Ok(*rule);
            }
        }
        Err(ParseError {
            unknown: rename_all_str,
        })
    }

    /// Apply a renaming rule to an enum variant, returning the version expected in the source.
    pub fn apply_to_variant(&self, variant: &str) -> String {
        match *self {
            None | PascalCase => variant.to_owned(),
            LowerCase => variant.to_ascii_lowercase(),
            UPPERCASE => variant.to_ascii_uppercase(),
            CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
            SnakeCase => {
                let mut snake = String::new();
                for (i, ch) in variant.char_indices() {
                    if i > 0 && ch.is_uppercase() {
                        snake.push('_');
                    }
                    snake.push(ch.to_ascii_lowercase());
                }
                snake
            }
            ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
            KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase
                .apply_to_variant(variant)
                .replace('_', "-"),
        }
    }

    /// Apply a renaming rule to a struct field, returning the version expected in the source.
    pub fn apply_to_field(&self, field: &str) -> String {
        match *self {
            None | LowerCase | SnakeCase => field.to_owned(),
            UPPERCASE => field.to_ascii_uppercase(),
            PascalCase => {
                let mut pascal = String::new();
                let mut capitalize = true;
                for ch in field.chars() {
                    if ch == '_' {
                        capitalize = true;
                    } else if capitalize {
                        pascal.push(ch.to_ascii_uppercase());
                        capitalize = false;
                    } else {
                        pascal.push(ch);
                    }
                }
                pascal
            }
            CamelCase => {
                let pascal = PascalCase.apply_to_field(field);
                pascal[..1].to_ascii_lowercase() + &pascal[1..]
            }
            ScreamingSnakeCase => field.to_ascii_uppercase(),
            KebabCase => field.replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
        }
    }
}

pub struct ParseError<'a> {
    unknown: &'a str,
}

impl<'a> Display for ParseError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "unknown rename rule for #[serde(rename_all = {:?})]",
            self.unknown,
        )
    }
}

#[test]
fn rename_variants() {
    for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
        (
            "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "VeryTasty",
            "verytasty",
            "VERYTASTY",
            "veryTasty",
            "very_tasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("A", "a", "A", "a", "a", "A", "a", "A"),
        ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_variant(original), original);
        assert_eq!(LowerCase.apply_to_variant(original), lower);
        assert_eq!(UPPERCASE.apply_to_variant(original), upper);
        assert_eq!(PascalCase.apply_to_variant(original), original);
        assert_eq!(CamelCase.apply_to_variant(original), camel);
        assert_eq!(SnakeCase.apply_to_variant(original), snake);
        assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
        assert_eq!(KebabCase.apply_to_variant(original), kebab);
        assert_eq!(
            ScreamingKebabCase.apply_to_variant(original),
            screaming_kebab
        );
    }
}

#[test]
fn rename_fields() {
    for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
        (
            "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "very_tasty",
            "VERY_TASTY",
            "VeryTasty",
            "veryTasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("a", "A", "A", "a", "A", "a", "A"),
        ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_field(original), original);
        assert_eq!(UPPERCASE.apply_to_field(original), upper);
        assert_eq!(PascalCase.apply_to_field(original), pascal);
        assert_eq!(CamelCase.apply_to_field(original), camel);
        assert_eq!(SnakeCase.apply_to_field(original), original);
        assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
        assert_eq!(KebabCase.apply_to_field(original), kebab);
        assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
    }
}
<commit_msg>Fix UPPERCASE rename rule variant to follow idiomatic variant naming<commit_after>//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).

// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;

use std::fmt::{self, Display};

use self::RenameRule::*;

/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(Copy, Clone, PartialEq)]
pub enum RenameRule {
    /// Don't apply a default rename rule.
    None,
    /// Rename direct children to "lowercase" style.
    LowerCase,
    /// Rename direct children to "UPPERCASE" style.
    UpperCase,
    /// Rename direct children to "PascalCase" style, as typically used for
    /// enum variants.
    PascalCase,
    /// Rename direct children to "camelCase" style.
    CamelCase,
    /// Rename direct children to "snake_case" style, as commonly used for
    /// fields.
    SnakeCase,
    /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
    /// used for constants.
    ScreamingSnakeCase,
    /// Rename direct children to "kebab-case" style.
    KebabCase,
    /// Rename direct children to "SCREAMING-KEBAB-CASE" style.
    ScreamingKebabCase,
}

static RENAME_RULES: &[(&str, RenameRule)] = &[
    ("lowercase", LowerCase),
    ("UPPERCASE", UpperCase),
    ("PascalCase", PascalCase),
    ("camelCase", CamelCase),
    ("snake_case", SnakeCase),
    ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
    ("kebab-case", KebabCase),
    ("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
];

impl RenameRule {
    pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
        for (name, rule) in RENAME_RULES {
            if rename_all_str == *name {
                return Ok(*rule);
            }
        }
        Err(ParseError {
            unknown: rename_all_str,
        })
    }

    /// Apply a renaming rule to an enum variant, returning the version expected in the source.
    pub fn apply_to_variant(&self, variant: &str) -> String {
        match *self {
            None | PascalCase => variant.to_owned(),
            LowerCase => variant.to_ascii_lowercase(),
            UpperCase => variant.to_ascii_uppercase(),
            CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
            SnakeCase => {
                let mut snake = String::new();
                for (i, ch) in variant.char_indices() {
                    if i > 0 && ch.is_uppercase() {
                        snake.push('_');
                    }
                    snake.push(ch.to_ascii_lowercase());
                }
                snake
            }
            ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
            KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase
                .apply_to_variant(variant)
                .replace('_', "-"),
        }
    }

    /// Apply a renaming rule to a struct field, returning the version expected in the source.
    pub fn apply_to_field(&self, field: &str) -> String {
        match *self {
            None | LowerCase | SnakeCase => field.to_owned(),
            UpperCase => field.to_ascii_uppercase(),
            PascalCase => {
                let mut pascal = String::new();
                let mut capitalize = true;
                for ch in field.chars() {
                    if ch == '_' {
                        capitalize = true;
                    } else if capitalize {
                        pascal.push(ch.to_ascii_uppercase());
                        capitalize = false;
                    } else {
                        pascal.push(ch);
                    }
                }
                pascal
            }
            CamelCase => {
                let pascal = PascalCase.apply_to_field(field);
                pascal[..1].to_ascii_lowercase() + &pascal[1..]
            }
            ScreamingSnakeCase => field.to_ascii_uppercase(),
            KebabCase => field.replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
        }
    }
}

pub struct ParseError<'a> {
    unknown: &'a str,
}

impl<'a> Display for ParseError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "unknown rename rule for #[serde(rename_all = {:?})]",
            self.unknown,
        )
    }
}

#[test]
fn rename_variants() {
    for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
        (
            "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "VeryTasty",
            "verytasty",
            "VERYTASTY",
            "veryTasty",
            "very_tasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("A", "a", "A", "a", "a", "A", "a", "A"),
        ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_variant(original), original);
        assert_eq!(LowerCase.apply_to_variant(original), lower);
        assert_eq!(UpperCase.apply_to_variant(original), upper);
        assert_eq!(PascalCase.apply_to_variant(original), original);
        assert_eq!(CamelCase.apply_to_variant(original), camel);
        assert_eq!(SnakeCase.apply_to_variant(original), snake);
        assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
        assert_eq!(KebabCase.apply_to_variant(original), kebab);
        assert_eq!(
            ScreamingKebabCase.apply_to_variant(original),
            screaming_kebab
        );
    }
}

#[test]
fn rename_fields() {
    for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
        (
            "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "very_tasty",
            "VERY_TASTY",
            "VeryTasty",
            "veryTasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("a", "A", "A", "a", "A", "a", "A"),
        ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_field(original), original);
        assert_eq!(UpperCase.apply_to_field(original), upper);
        assert_eq!(PascalCase.apply_to_field(original), pascal);
        assert_eq!(CamelCase.apply_to_field(original), camel);
        assert_eq!(SnakeCase.apply_to_field(original), original);
        assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
        assert_eq!(KebabCase.apply_to_field(original), kebab);
        assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
    }
}
<|endoftext|>


<commit_before>//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.

use rustc_hir::Constness;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_span::Span;

/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
///
/// ```text
/// trait Foo: Bar + Baz { }
///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
///
/// fn foo<T: Bar + Baz>() { }
///           ^^^^^^^^^ bounding the type parameter `T`
///
/// impl dyn Bar + Baz
///          ^^^^^^^^^ bounding the forgotten dynamic type
/// ```
///
/// Our representation is a bit mixed here -- in some cases, we
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
    /// A list of region bounds on the (implicit) self type. So if you
    /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
    /// the `T` is not explicitly included).
    pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,

    /// A list of trait bounds. So if you had `T: Debug` this would be
    /// `T: Debug`. Note that the self-type is explicit here.
    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,

    /// A list of projection equality bounds. So if you had `T:
    /// Iterator<Item = u32>` this would include `<T as
    /// Iterator>::Item => u32`. Note that the self-type is explicit
    /// here.
    pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,

    /// `Some` if there is *no* `?Sized` predicate. The `span`
    /// is the location in the source of the `T` declaration which can
    /// be cited as the source of the `T: Sized` requirement.
    pub implicitly_sized: Option<Span>,
}

impl<'tcx> Bounds<'tcx> {
    /// Converts a bounds list into a flat set of predicates (like
    /// where-clauses). Because some of our bounds listings (e.g.,
    /// regions) don't include the self-type, you must supply the
    /// self-type here (the `param_ty` parameter).
    pub fn predicates(
        &self,
        tcx: TyCtxt<'tcx>,
        param_ty: Ty<'tcx>,
    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
        // If it could be sized, and is, add the `Sized` predicate.
        let sized_predicate = self.implicitly_sized.and_then(|span| {
            tcx.lang_items().sized_trait().map(|sized| {
                let trait_ref = ty::Binder::bind(ty::TraitRef {
                    def_id: sized,
                    substs: tcx.mk_substs_trait(param_ty, &[]),
                });
                (trait_ref.without_const().to_predicate(tcx), span)
            })
        });

        sized_predicate
            .into_iter()
            .chain(
                self.region_bounds
                    .iter()
                    .map(|&(region_bound, span)| {
                        let outlives = ty::OutlivesPredicate(param_ty, region_bound);
                        (ty::Binder::bind(outlives).to_predicate(tcx), span)
                    })
                    .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
                        let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                        (predicate, span)
                    }))
                    .chain(
                        self.projection_bounds
                            .iter()
                            .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
                    ),
            )
            .collect()
    }
}
<commit_msg>Unnest some .chain calls, so it's clearer what's going on.<commit_after>//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.

use rustc_hir::Constness;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_span::Span;

/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
///
/// ```text
/// trait Foo: Bar + Baz { }
///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
///
/// fn foo<T: Bar + Baz>() { }
///           ^^^^^^^^^ bounding the type parameter `T`
///
/// impl dyn Bar + Baz
///          ^^^^^^^^^ bounding the forgotten dynamic type
/// ```
///
/// Our representation is a bit mixed here -- in some cases, we
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
    /// A list of region bounds on the (implicit) self type. So if you
    /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
    /// the `T` is not explicitly included).
    pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,

    /// A list of trait bounds. So if you had `T: Debug` this would be
    /// `T: Debug`. Note that the self-type is explicit here.
    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,

    /// A list of projection equality bounds. So if you had `T:
    /// Iterator<Item = u32>` this would include `<T as
    /// Iterator>::Item => u32`. Note that the self-type is explicit
    /// here.
    pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,

    /// `Some` if there is *no* `?Sized` predicate. The `span`
    /// is the location in the source of the `T` declaration which can
    /// be cited as the source of the `T: Sized` requirement.
    pub implicitly_sized: Option<Span>,
}

impl<'tcx> Bounds<'tcx> {
    /// Converts a bounds list into a flat set of predicates (like
    /// where-clauses). Because some of our bounds listings (e.g.,
    /// regions) don't include the self-type, you must supply the
    /// self-type here (the `param_ty` parameter).
    pub fn predicates(
        &self,
        tcx: TyCtxt<'tcx>,
        param_ty: Ty<'tcx>,
    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
        // If it could be sized, and is, add the `Sized` predicate.
        let sized_predicate = self.implicitly_sized.and_then(|span| {
            tcx.lang_items().sized_trait().map(|sized| {
                let trait_ref = ty::Binder::bind(ty::TraitRef {
                    def_id: sized,
                    substs: tcx.mk_substs_trait(param_ty, &[]),
                });
                (trait_ref.without_const().to_predicate(tcx), span)
            })
        });

        sized_predicate
            .into_iter()
            .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
                let outlives = ty::OutlivesPredicate(param_ty, region_bound);
                (ty::Binder::bind(outlives).to_predicate(tcx), span)
            }))
            .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
                let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                (predicate, span)
            }))
            .chain(
                self.projection_bounds
                    .iter()
                    .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
            )
            .collect()
    }
}
<|endoftext|>


<commit_before>use linalg::vector::Vector;

/// The Kernel trait
///
/// Requires a function mapping two vectors to a scalar.
pub trait Kernel {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64;
}

/// Squared exponential kernel
///
/// Equivalently a gaussian function.
///
/// The kernel function is given by:
///
/// f(x1,x2) = A _exp_(-||x1-x2||^2 / 2(l^2))
///
/// Where A is the amplitude and l the length scale.
pub struct SquaredExp {
    ls: f64,
    ampl: f64,
}

impl SquaredExp {

    /// Construct a new squared exponential kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::new(2f64, 1f64);
    /// ```
    pub fn new(ls: f64, ampl: f64) -> SquaredExp {
        SquaredExp {
            ls: ls,
            ampl: ampl,
        }
    }
}

impl Default for SquaredExp {

    /// Constructs the default Squared Exp kernel.
    ///
    /// The default settings are:
    /// - length scale = 1
    /// - amplitude = 1
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::default();
    /// ```
    fn default() -> SquaredExp {
        SquaredExp {
            ls: 1f64,
            ampl: 1f64,
        }
    }
}

impl Kernel for SquaredExp {
    /// The squared exponential kernel function.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let v1 = Vector::new(x1.to_vec());
        let v2 = Vector::new(x2.to_vec());

        let x = -(&v1 - &v2).dot(&(v1 - v2)) / (2f64 * self.ls * self.ls);
        (self.ampl * x.exp())
    }
}
<commit_msg>Module docs for kernels<commit_after>//! Module for kernels
//!
//! Currently used within Gaussian Processes.

use linalg::vector::Vector;

/// The Kernel trait
///
/// Requires a function mapping two vectors to a scalar.
pub trait Kernel {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64;
}

/// Squared exponential kernel
///
/// Equivalently a gaussian function.
///
/// The kernel function is given by:
///
/// f(x1,x2) = A _exp_(-||x1-x2||^2 / 2(l^2))
///
/// Where A is the amplitude and l the length scale.
pub struct SquaredExp {
    ls: f64,
    ampl: f64,
}

impl SquaredExp {

    /// Construct a new squared exponential kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::new(2f64, 1f64);
    /// ```
    pub fn new(ls: f64, ampl: f64) -> SquaredExp {
        SquaredExp {
            ls: ls,
            ampl: ampl,
        }
    }
}

impl Default for SquaredExp {

    /// Constructs the default Squared Exp kernel.
    ///
    /// The default settings are:
    /// - length scale = 1
    /// - amplitude = 1
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::default();
    /// ```
    fn default() -> SquaredExp {
        SquaredExp {
            ls: 1f64,
            ampl: 1f64,
        }
    }
}

impl Kernel for SquaredExp {
    /// The squared exponential kernel function.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let v1 = Vector::new(x1.to_vec());
        let v2 = Vector::new(x2.to_vec());

        let x = -(&v1 - &v2).dot(&(v1 - v2)) / (2f64 * self.ls * self.ls);
        (self.ampl * x.exp())
    }
}
<|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 ipc_channel::ipc::IpcSharedMemory;
use piston_image::{self, DynamicImage, ImageFormat};
use std::fmt;
use webrender_api;

#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum PixelFormat {
    /// Luminance channel only
    K8,
    /// Luminance + alpha
    KA8,
    /// RGB, 8 bits per channel
    RGB8,
    /// RGB + alpha, 8 bits per channel
    BGRA8,
}

#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub struct Image {
    pub width: u32,
    pub height: u32,
    pub format: PixelFormat,
    #[ignore_malloc_size_of = "Defined in ipc-channel"]
    pub bytes: IpcSharedMemory,
    #[ignore_malloc_size_of = "Defined in webrender_api"]
    pub id: Option<webrender_api::ImageKey>,
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Image {{ width: {}, height: {}, format: {:?}, ..., id: {:?} }}",
               self.width, self.height, self.format, self.id)
    }
}

#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub struct ImageMetadata {
    pub width: u32,
    pub height: u32,
}

// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.

// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
fn byte_swap_and_premultiply(data: &mut [u8]) {
    let length = data.len();

    let mut i = 0;
    while i < length {
        let r = data[i + 2];
        let g = data[i + 1];
        let b = data[i + 0];

        data[i + 0] = r;
        data[i + 1] = g;
        data[i + 2] = b;

        i += 4;
    }
}

pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
    if buffer.is_empty() {
        return None;
    }

    let image_fmt_result = detect_image_format(buffer);
    match image_fmt_result {
        Err(msg) => {
            debug!("{}", msg);
            None
        },
        Ok(_) => {
            match piston_image::load_from_memory(buffer) {
                Ok(image) => {
                    let mut rgba = match image {
                        DynamicImage::ImageRgba8(rgba) => rgba,
                        image => image.to_rgba(),
                    };
                    byte_swap_and_premultiply(&mut *rgba);
                    Some(Image {
                        width: rgba.width(),
                        height: rgba.height(),
                        format: PixelFormat::BGRA8,
                        bytes: IpcSharedMemory::from_bytes(&*rgba),
                        id: None,
                    })
                },
                Err(e) => {
                    debug!("Image decoding error: {:?}", e);
                    None
                },
            }
        },
    }
}

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
pub fn detect_image_format(buffer: &[u8]) -> Result<ImageFormat, &str> {
    if is_gif(buffer) {
        Ok(ImageFormat::GIF)
    } else if is_jpeg(buffer) {
        Ok(ImageFormat::JPEG)
    } else if is_png(buffer) {
        Ok(ImageFormat::PNG)
    } else if is_bmp(buffer) {
        Ok(ImageFormat::BMP)
    } else if is_ico(buffer) {
        Ok(ImageFormat::ICO)
    } else {
        Err("Image Format Not Supported")
    }
}

fn is_gif(buffer: &[u8]) -> bool {
    buffer.starts_with(b"GIF87a") || buffer.starts_with(b"GIF89a")
}

fn is_jpeg(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0xff, 0xd8, 0xff])
}

fn is_png(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
}

fn is_bmp(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x42, 0x4D])
}

fn is_ico(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x00, 0x00, 0x01, 0x00])
}
<commit_msg>Rename byte_swap_and_premultiply to byte_swap_colors_inplace<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 ipc_channel::ipc::IpcSharedMemory;
use piston_image::{self, DynamicImage, ImageFormat};
use std::fmt;
use webrender_api;

#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum PixelFormat {
    /// Luminance channel only
    K8,
    /// Luminance + alpha
    KA8,
    /// RGB, 8 bits per channel
    RGB8,
    /// RGB + alpha, 8 bits per channel
    BGRA8,
}

#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
pub struct Image {
    pub width: u32,
    pub height: u32,
    pub format: PixelFormat,
    #[ignore_malloc_size_of = "Defined in ipc-channel"]
    pub bytes: IpcSharedMemory,
    #[ignore_malloc_size_of = "Defined in webrender_api"]
    pub id: Option<webrender_api::ImageKey>,
}

impl fmt::Debug for Image {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Image {{ width: {}, height: {}, format: {:?}, ..., id: {:?} }}",
               self.width, self.height, self.format, self.id)
    }
}

#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub struct ImageMetadata {
    pub width: u32,
    pub height: u32,
}

// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.

// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
fn byte_swap_colors_inplace(data: &mut [u8]) {
    let length = data.len();

    let mut i = 0;
    while i < length {
        let r = data[i + 2];
        let g = data[i + 1];
        let b = data[i + 0];

        data[i + 0] = r;
        data[i + 1] = g;
        data[i + 2] = b;

        i += 4;
    }
}

pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
    if buffer.is_empty() {
        return None;
    }

    let image_fmt_result = detect_image_format(buffer);
    match image_fmt_result {
        Err(msg) => {
            debug!("{}", msg);
            None
        },
        Ok(_) => {
            match piston_image::load_from_memory(buffer) {
                Ok(image) => {
                    let mut rgba = match image {
                        DynamicImage::ImageRgba8(rgba) => rgba,
                        image => image.to_rgba(),
                    };
                    byte_swap_colors_inplace(&mut *rgba);
                    Some(Image {
                        width: rgba.width(),
                        height: rgba.height(),
                        format: PixelFormat::BGRA8,
                        bytes: IpcSharedMemory::from_bytes(&*rgba),
                        id: None,
                    })
                },
                Err(e) => {
                    debug!("Image decoding error: {:?}", e);
                    None
                },
            }
        },
    }
}

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
pub fn detect_image_format(buffer: &[u8]) -> Result<ImageFormat, &str> {
    if is_gif(buffer) {
        Ok(ImageFormat::GIF)
    } else if is_jpeg(buffer) {
        Ok(ImageFormat::JPEG)
    } else if is_png(buffer) {
        Ok(ImageFormat::PNG)
    } else if is_bmp(buffer) {
        Ok(ImageFormat::BMP)
    } else if is_ico(buffer) {
        Ok(ImageFormat::ICO)
    } else {
        Err("Image Format Not Supported")
    }
}

fn is_gif(buffer: &[u8]) -> bool {
    buffer.starts_with(b"GIF87a") || buffer.starts_with(b"GIF89a")
}

fn is_jpeg(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0xff, 0xd8, 0xff])
}

fn is_png(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
}

fn is_bmp(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x42, 0x4D])
}

fn is_ico(buffer: &[u8]) -> bool {
    buffer.starts_with(&[0x00, 0x00, 0x01, 0x00])
}
<|endoftext|>


<commit_before>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate bincode;
extern crate rustc_serialize;

use self::bincode::SizeLimit;
use rustc_serialize::{Decodable, Decoder};

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  i64,
    pub action:         i32,
    pub transaction_id: i32,
}

#[derive(Debug, RustcEncodable)]
struct ConnectionResponse {
    action:         i32,
    transaction_id: i32,
    connection_id:  i64,
}

#[derive(Debug)]
pub struct ClientAnnounce {
    pub info_hash:  Vec<u8>,
    pub peer_id:    Vec<u8>,
    pub downloaded: i64,
    pub remaining:  i64,
    pub uploaded:   i64,
    pub event:      i32,
    pub ip:         u32,
    pub key:        u32,
    pub num_want:   i32,
    pub port:       u16,
}

impl Decodable for ClientAnnounce {
    fn decode<D: Decoder>(d: &mut D) -> Result<ClientAnnounce, D::Error> {
        let mut info_hash = Vec::new();
        for i in 0..20 {
            info_hash.push(try!(d.read_u8()));
        }
        let mut peer_id = Vec::new();
        for i in 0..20 {
            peer_id.push(try!(d.read_u8()));
        }
        Ok(ClientAnnounce {
            info_hash:  info_hash,
            peer_id:    peer_id,
            downloaded: try!(d.read_i64()),
            remaining:  try!(d.read_i64()),
            uploaded:   try!(d.read_i64()),
            event:      try!(d.read_i32()),
            ip:         try!(d.read_u32()),
            key:        try!(d.read_u32()),
            num_want:   try!(d.read_i32()),
            port:       try!(d.read_u16()),
        })
    }
}

#[derive(Debug, RustcEncodable)]
struct ServerAnnounce {
    action:         i32,
    transaction_id: i32,
    interval:       i32,
    leechers:       i32,
    seeders:        i32,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: i64, tran_id: i32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}

pub fn decode_client_announce(packet: &[u8]) -> ClientAnnounce {
    bincode::decode(&packet).unwrap()
}

pub fn encode_server_announce(transaction_id: i32, mut swarm: Vec<(i32,i32)>, num_want: i32, leechers: i32, seeders: i32) -> Vec<u8> {
    let packet = ServerAnnounce {
        action:         1,              // Announce is always 1
        transaction_id: transaction_id,
        interval:       1800,           // 30min = 1800sec
        leechers:       leechers,
        seeders:        seeders,
    };

    let mut packet = bincode::encode(&packet, SizeLimit::Infinite).unwrap();

    // Truncate the vector if num_want is smaller than the vector length
    if (num_want >= 0) && (num_want < swarm.len() as i32) {
        swarm.truncate(num_want as usize);
    }

    for peer in &mut swarm {
        let (i, p): (i32, i32) = *peer;
        packet.append(&mut bincode::encode(&i, SizeLimit::Infinite).unwrap());
        packet.append(&mut bincode::encode(&(p as u16), SizeLimit::Infinite).unwrap());
    }

    packet
}

pub fn encode_error(transaction_id: i32, error_string: &'static str) -> Vec<u8> {
    let mut packet: Vec<u8> = Vec::new();

    // Action (3 == Error)
    packet.append(&mut bincode::encode(&3i32, SizeLimit::Infinite).unwrap());
    // Transaction_id
    packet.append(&mut bincode::encode(&transaction_id, SizeLimit::Infinite).unwrap());
    // Finally, the message
    packet.append(&mut bincode::encode(&error_string, SizeLimit::Infinite).unwrap());

    // Return the packet
    packet
}

<commit_msg>cleanup some warnings<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate bincode;
extern crate rustc_serialize;

use self::bincode::SizeLimit;
use rustc_serialize::{Decodable, Decoder};

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  i64,
    pub action:         i32,
    pub transaction_id: i32,
}

#[derive(Debug, RustcEncodable)]
struct ConnectionResponse {
    action:         i32,
    transaction_id: i32,
    connection_id:  i64,
}

#[derive(Debug)]
pub struct ClientAnnounce {
    pub info_hash:  Vec<u8>,
    pub peer_id:    Vec<u8>,
    pub downloaded: i64,
    pub remaining:  i64,
    pub uploaded:   i64,
    pub event:      i32,
    pub ip:         u32,
    pub key:        u32,
    pub num_want:   i32,
    pub port:       u16,
}

impl Decodable for ClientAnnounce {
    fn decode<D: Decoder>(d: &mut D) -> Result<ClientAnnounce, D::Error> {
        let mut info_hash = Vec::new();
        for _ in 0..20 {
            info_hash.push(try!(d.read_u8()));
        }
        let mut peer_id = Vec::new();
        for _ in 0..20 {
            peer_id.push(try!(d.read_u8()));
        }
        Ok(ClientAnnounce {
            info_hash:  info_hash,
            peer_id:    peer_id,
            downloaded: try!(d.read_i64()),
            remaining:  try!(d.read_i64()),
            uploaded:   try!(d.read_i64()),
            event:      try!(d.read_i32()),
            ip:         try!(d.read_u32()),
            key:        try!(d.read_u32()),
            num_want:   try!(d.read_i32()),
            port:       try!(d.read_u16()),
        })
    }
}

#[derive(Debug, RustcEncodable)]
struct ServerAnnounce {
    action:         i32,
    transaction_id: i32,
    interval:       i32,
    leechers:       i32,
    seeders:        i32,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: i64, tran_id: i32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}

pub fn decode_client_announce(packet: &[u8]) -> ClientAnnounce {
    bincode::decode(&packet).unwrap()
}

pub fn encode_server_announce(transaction_id: i32, mut swarm: Vec<(i32,i32)>, num_want: i32, leechers: i32, seeders: i32) -> Vec<u8> {
    let packet = ServerAnnounce {
        action:         1,              // Announce is always 1
        transaction_id: transaction_id,
        interval:       1800,           // 30min = 1800sec
        leechers:       leechers,
        seeders:        seeders,
    };

    let mut packet = bincode::encode(&packet, SizeLimit::Infinite).unwrap();

    // Truncate the vector if num_want is smaller than the vector length
    if (num_want >= 0) && (num_want < swarm.len() as i32) {
        swarm.truncate(num_want as usize);
    }

    for peer in &mut swarm {
        let (i, p): (i32, i32) = *peer;
        packet.append(&mut bincode::encode(&i, SizeLimit::Infinite).unwrap());
        packet.append(&mut bincode::encode(&(p as u16), SizeLimit::Infinite).unwrap());
    }

    packet
}

pub fn encode_error(transaction_id: i32, error_string: &'static str) -> Vec<u8> {
    let mut packet: Vec<u8> = Vec::new();

    // Action (3 == Error)
    packet.append(&mut bincode::encode(&3i32, SizeLimit::Infinite).unwrap());
    // Transaction_id
    packet.append(&mut bincode::encode(&transaction_id, SizeLimit::Infinite).unwrap());
    // Finally, the message
    packet.append(&mut bincode::encode(&error_string, SizeLimit::Infinite).unwrap());

    // Return the packet
    packet
}

<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use std::os::unix::fs::OpenOptionsExt;
use std::path::PathBuf;
use std::process::{Command, Stdio};

use handlebars::Handlebars;

use error::{Error, Result};
use hcore::util;
use package::Package;
use service_config::{ServiceConfig, never_escape_fn};
use util::convert;
use util::handlebars_helpers;
use util::users as hab_users;

pub const HOOK_PERMISSIONS: u32 = 0o755;
static LOGKEY: &'static str = "PH";

#[derive(Debug, Clone)]
pub enum HookType {
    HealthCheck,
    Reconfigure,
    FileUpdated,
    Run,
    Init,
}

impl fmt::Display for HookType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &HookType::Init => write!(f, "init"),
            &HookType::HealthCheck => write!(f, "health_check"),
            &HookType::FileUpdated => write!(f, "file_updated"),
            &HookType::Reconfigure => write!(f, "reconfigure"),
            &HookType::Run => write!(f, "run"),
        }
    }
}

#[derive(Debug)]
pub struct Hook {
    pub htype: HookType,
    pub template: PathBuf,
    pub path: PathBuf,
    pub user: String,
    pub group: String,
}

impl Hook {
    pub fn new(htype: HookType,
               template: PathBuf,
               path: PathBuf,
               user: String,
               group: String)
               -> Self {
        Hook {
            htype: htype,
            template: template,
            path: path,
            user: user,
            group: group,
        }
    }

    pub fn run(&self, context: Option<&ServiceConfig>) -> Result<String> {
        try!(self.compile(context));
        let mut cmd = Command::new(&self.path);
        try!(self.run_platform(&mut cmd));
        let mut child = try!(cmd.spawn());
        {
            let mut c_stdout = match child.stdout {
                Some(ref mut s) => s,
                None => {
                    return Err(sup_error!(Error::HookFailed(self.htype.clone(),
                                                            -1,
                                                            String::from("Failed"))));
                }
            };
            let preamble_str = format!("{}", &self.htype);
            let mut line = output_format!(preamble & preamble_str, "");
            loop {
                let mut buf = [0u8; 1]; // Our byte buffer
                let len = try!(c_stdout.read(&mut buf));
                match len {
                    0 => {
                        // 0 == EOF, so stop writing and finish progress
                        break;
                    }
                    _ => {
                        // Write the buffer to the BufWriter on the Heap
                        let buf_string = String::from_utf8_lossy(&buf[0..len]);
                        line.push_str(&buf_string);
                        if line.contains("\n") {
                            print!("{}", line);
                            line = output_format!(preamble & preamble_str, "");
                        }
                    }
                }
            }
        }
        let exit_status = try!(child.wait());
        if exit_status.success() {
            Ok(String::from("Finished"))
        } else {
            Err(sup_error!(Error::HookFailed(self.htype.clone(),
                                             exit_status.code().unwrap_or(-1),
                                             String::from("Failed"))))
        }
    }

    #[cfg(any(target_os="linux", target_os="macos"))]
    fn run_platform(&self, cmd: &mut Command) -> Result<()> {
        use std::os::unix::process::CommandExt;
        let uid = hab_users::user_name_to_uid(&self.user);
        let gid = hab_users::group_name_to_gid(&self.group);
        if let None = uid {
            panic!("Can't determine uid");
        }

        if let None = gid {
            panic!("Can't determine gid");
        }

        let uid = uid.unwrap();
        let gid = gid.unwrap();
        cmd.stdin(Stdio::null())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .uid(uid)
            .gid(gid);
        Ok(())
    }

    #[cfg(target_os = "windows")]
    fn run_platform(&self, cmd: &mut Command) -> Result<()> {
        unimplemented!();
    }

    pub fn compile(&self, context: Option<&ServiceConfig>) -> Result<()> {
        if let Some(ctx) = context {
            debug!("Rendering hook {:?}", self);
            let mut handlebars = Handlebars::new();
            handlebars.register_helper("json", Box::new(handlebars_helpers::json_helper));
            handlebars.register_helper("toml", Box::new(handlebars_helpers::toml_helper));
            handlebars.register_escape_fn(never_escape_fn);
            try!(handlebars.register_template_file("hook", &self.template));
            let toml = try!(ctx.to_toml());
            let svc_data = convert::toml_to_json(toml);
            let data = try!(handlebars.render("hook", &svc_data));
            let mut file = try!(OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .read(true)
                .mode(0o770)
                .open(&self.path));
            try!(write!(&mut file, "{}", data));
            try!(util::perm::set_owner(&self.path, &self.user, &self.group));
            try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
            Ok(())
        } else {
            try!(fs::copy(&self.template, &self.path));
            try!(util::perm::set_owner(&self.path, &self.user, &self.group));
            try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
            Ok(())
        }
    }
}

pub struct HookTable<'a> {
    pub package: &'a Package,
    pub init_hook: Option<Hook>,
    pub health_check_hook: Option<Hook>,
    pub reconfigure_hook: Option<Hook>,
    pub file_updated_hook: Option<Hook>,
    pub run_hook: Option<Hook>,
}

impl<'a> HookTable<'a> {
    pub fn new(package: &'a Package) -> Self {
        HookTable {
            package: package,
            init_hook: None,
            health_check_hook: None,
            reconfigure_hook: None,
            file_updated_hook: None,
            run_hook: None,
        }
    }

    pub fn load_hooks(&mut self) -> &mut Self {
        let path = &self.package.config_from().join("hooks");
        match fs::metadata(path) {
            Ok(meta) => {
                if meta.is_dir() {
                    self.init_hook = self.load_hook(HookType::Init);
                    self.file_updated_hook = self.load_hook(HookType::FileUpdated);
                    self.reconfigure_hook = self.load_hook(HookType::Reconfigure);
                    self.health_check_hook = self.load_hook(HookType::HealthCheck);
                    self.run_hook = self.load_hook(HookType::Run);
                }
            }
            Err(_) => {}
        }
        self
    }

    fn load_hook(&self, hook_type: HookType) -> Option<Hook> {
        let template = self.package.hook_template_path(&hook_type);
        let concrete = self.package.hook_path(&hook_type);
        let (user, group) = hab_users::get_user_and_group(&self.package.pkg_install)
            .expect("Can't determine user:group");

        match fs::metadata(&template) {
            Ok(_) => Some(Hook::new(hook_type, template, concrete, user, group)),
            Err(_) => None,
        }
    }
}
<commit_msg>write hooks file using ::create to be os portable<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::fs::{self, File, OpenOptions};
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Stdio};

use handlebars::Handlebars;

use error::{Error, Result};
use hcore::util;
use package::Package;
use service_config::{ServiceConfig, never_escape_fn};
use util::convert;
use util::handlebars_helpers;
use util::users as hab_users;

pub const HOOK_PERMISSIONS: u32 = 0o755;
static LOGKEY: &'static str = "PH";

#[derive(Debug, Clone)]
pub enum HookType {
    HealthCheck,
    Reconfigure,
    FileUpdated,
    Run,
    Init,
}

impl fmt::Display for HookType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &HookType::Init => write!(f, "init"),
            &HookType::HealthCheck => write!(f, "health_check"),
            &HookType::FileUpdated => write!(f, "file_updated"),
            &HookType::Reconfigure => write!(f, "reconfigure"),
            &HookType::Run => write!(f, "run"),
        }
    }
}

#[derive(Debug)]
pub struct Hook {
    pub htype: HookType,
    pub template: PathBuf,
    pub path: PathBuf,
    pub user: String,
    pub group: String,
}

impl Hook {
    pub fn new(htype: HookType,
               template: PathBuf,
               path: PathBuf,
               user: String,
               group: String)
               -> Self {
        Hook {
            htype: htype,
            template: template,
            path: path,
            user: user,
            group: group,
        }
    }

    pub fn run(&self, context: Option<&ServiceConfig>) -> Result<String> {
        try!(self.compile(context));
        let mut cmd = Command::new(&self.path);
        try!(self.run_platform(&mut cmd));
        let mut child = try!(cmd.spawn());
        {
            let mut c_stdout = match child.stdout {
                Some(ref mut s) => s,
                None => {
                    return Err(sup_error!(Error::HookFailed(self.htype.clone(),
                                                            -1,
                                                            String::from("Failed"))));
                }
            };
            let preamble_str = format!("{}", &self.htype);
            let mut line = output_format!(preamble & preamble_str, "");
            loop {
                let mut buf = [0u8; 1]; // Our byte buffer
                let len = try!(c_stdout.read(&mut buf));
                match len {
                    0 => {
                        // 0 == EOF, so stop writing and finish progress
                        break;
                    }
                    _ => {
                        // Write the buffer to the BufWriter on the Heap
                        let buf_string = String::from_utf8_lossy(&buf[0..len]);
                        line.push_str(&buf_string);
                        if line.contains("\n") {
                            print!("{}", line);
                            line = output_format!(preamble & preamble_str, "");
                        }
                    }
                }
            }
        }
        let exit_status = try!(child.wait());
        if exit_status.success() {
            Ok(String::from("Finished"))
        } else {
            Err(sup_error!(Error::HookFailed(self.htype.clone(),
                                             exit_status.code().unwrap_or(-1),
                                             String::from("Failed"))))
        }
    }

    #[cfg(any(target_os="linux", target_os="macos"))]
    fn run_platform(&self, cmd: &mut Command) -> Result<()> {
        use std::os::unix::process::CommandExt;
        let uid = hab_users::user_name_to_uid(&self.user);
        let gid = hab_users::group_name_to_gid(&self.group);
        if let None = uid {
            panic!("Can't determine uid");
        }

        if let None = gid {
            panic!("Can't determine gid");
        }

        let uid = uid.unwrap();
        let gid = gid.unwrap();
        cmd.stdin(Stdio::null())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .uid(uid)
            .gid(gid);
        Ok(())
    }

    #[cfg(target_os = "windows")]
    fn run_platform(&self, cmd: &mut Command) -> Result<()> {
        unimplemented!();
    }

    pub fn compile(&self, context: Option<&ServiceConfig>) -> Result<()> {
        if let Some(ctx) = context {
            debug!("Rendering hook {:?}", self);
            let mut handlebars = Handlebars::new();
            handlebars.register_helper("json", Box::new(handlebars_helpers::json_helper));
            handlebars.register_helper("toml", Box::new(handlebars_helpers::toml_helper));
            handlebars.register_escape_fn(never_escape_fn);
            try!(handlebars.register_template_file("hook", &self.template));
            let toml = try!(ctx.to_toml());
            let svc_data = convert::toml_to_json(toml);
            let data = try!(handlebars.render("hook", &svc_data));
            let mut file = try!(File::create(&self.path));
            try!(file.write_all(data.as_bytes()));
            try!(util::perm::set_owner(&self.path, &self.user, &self.group));
            try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
            Ok(())
        } else {
            try!(fs::copy(&self.template, &self.path));
            try!(util::perm::set_owner(&self.path, &self.user, &self.group));
            try!(util::perm::set_permissions(&self.path, HOOK_PERMISSIONS));
            Ok(())
        }
    }
}

pub struct HookTable<'a> {
    pub package: &'a Package,
    pub init_hook: Option<Hook>,
    pub health_check_hook: Option<Hook>,
    pub reconfigure_hook: Option<Hook>,
    pub file_updated_hook: Option<Hook>,
    pub run_hook: Option<Hook>,
}

impl<'a> HookTable<'a> {
    pub fn new(package: &'a Package) -> Self {
        HookTable {
            package: package,
            init_hook: None,
            health_check_hook: None,
            reconfigure_hook: None,
            file_updated_hook: None,
            run_hook: None,
        }
    }

    pub fn load_hooks(&mut self) -> &mut Self {
        let path = &self.package.config_from().join("hooks");
        match fs::metadata(path) {
            Ok(meta) => {
                if meta.is_dir() {
                    self.init_hook = self.load_hook(HookType::Init);
                    self.file_updated_hook = self.load_hook(HookType::FileUpdated);
                    self.reconfigure_hook = self.load_hook(HookType::Reconfigure);
                    self.health_check_hook = self.load_hook(HookType::HealthCheck);
                    self.run_hook = self.load_hook(HookType::Run);
                }
            }
            Err(_) => {}
        }
        self
    }

    fn load_hook(&self, hook_type: HookType) -> Option<Hook> {
        let template = self.package.hook_template_path(&hook_type);
        let concrete = self.package.hook_path(&hook_type);
        let (user, group) = hab_users::get_user_and_group(&self.package.pkg_install)
            .expect("Can't determine user:group");

        match fs::metadata(&template) {
            Ok(_) => Some(Hook::new(hook_type, template, concrete, user, group)),
            Err(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>
use std::error::Error as StdError;
use std::fmt;

#[derive(PartialEq)]
pub enum ParseError {
    Eof,
    NotFound,
    Expected(Vec<u8>),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof => "End of File",
            ParseError::NotFound => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Eof => None,
            ParseError::NotFound => None,
            ParseError::Expected(_) => None,
        }
    }
}
<commit_msg>rfc5322: ParseError::ExpectedType<commit_after>
use std::error::Error as StdError;
use std::fmt;

#[derive(PartialEq)]
pub enum ParseError {
    Eof,
    NotFound,
    Expected(Vec<u8>),
    ExpectedType(&'static str),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof => "End of File",
            ParseError::NotFound => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
            ParseError::ExpectedType(_) => "Expectation Failed",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Eof => None,
            ParseError::NotFound => None,
            ParseError::Expected(_) => None,
            ParseError::ExpectedType(_) => None,
        }
    }
}
<|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::ptr;
use std::sync::Arc;
use std::time::Duration;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

/// Returned when you submit one or multiple command buffers.
///
/// This object holds the resources that are used by the GPU and that must be kept alive for at
/// least as long as the GPU is executing the submission. Therefore destroying a `Submission`
/// object will block until the GPU is finished executing.
///
/// Whenever you submit a command buffer, you are encouraged to store the returned `Submission`
/// in a long-living container such as a `Vec`. From time to time, you can clean the obsolete
/// objects by checking whether `destroying_would_block()` returns false. For example, if you use
/// a `Vec` you can do `vec.retain(|s| s.destroying_would_block())`.
// TODO: docs
// # Leak safety
//
// The `Submission` object can hold borrows of command buffers. In order for it to be safe to leak
// a `Submission`, the borrowed object themselves must be protected by a fence.
#[must_use]
pub struct Submission {
    fence: Arc<Fence>,      // TODO: make optional
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

impl Submission {
    /// Returns `true` if destroying this `Submission` object would block the CPU for some time.
    #[inline]
    pub fn destroying_would_block(&self) -> bool {
        !self.finished()
    }

    /// Returns `true` if the GPU has finished executing this submission.
    #[inline]
    pub fn finished(&self) -> bool {
        self.fence.ready().unwrap_or(false)     // TODO: what to do in case of error?
    }
}

impl Drop for Submission {
    fn drop(&mut self) {
        self.fence.wait(Duration::from_secs(10)).unwrap();      // TODO: handle some errors
    }
}

trait KeepAlive {}
impl<T> KeepAlive for T {}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) -> Submission {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits, keep_alive }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // TODO: for now we always create a Fence in order to put it in the submission
        let fence = fence.unwrap_or_else(|| Fence::new(queue.device().clone()));

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            //let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            let fence = fence.internal_object();
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }

        Submission {
            keep_alive: keep_alive,
            fence: fence,
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
            keep_alive: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device);
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        // TODO: not implemented ; where to store the created command buffers?
        assert!(current_infos.pre_pipeline_barrier.is_empty());
        assert!(current_infos.post_pipeline_barrier.is_empty());

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            infos.keep_alive.push(semaphore);
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            infos.keep_alive.push(semaphore);
            new_submit.signalSemaphoreCount += 1;
        }

        infos.command_buffers.push(current.inner().internal_object());

        infos.submits.push(new_submit);

        infos
    }
}
<commit_msg>Add submitting temporary command buffers<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.

use std::ptr;
use std::sync::Arc;
use std::time::Duration;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::Kind;
use command_buffer::sys::Flags;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Device;
use device::Queue;
use framebuffer::EmptySinglePassRenderPass;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

/// Returned when you submit one or multiple command buffers.
///
/// This object holds the resources that are used by the GPU and that must be kept alive for at
/// least as long as the GPU is executing the submission. Therefore destroying a `Submission`
/// object will block until the GPU is finished executing.
///
/// Whenever you submit a command buffer, you are encouraged to store the returned `Submission`
/// in a long-living container such as a `Vec`. From time to time, you can clean the obsolete
/// objects by checking whether `destroying_would_block()` returns false. For example, if you use
/// a `Vec` you can do `vec.retain(|s| s.destroying_would_block())`.
// TODO: docs
// # Leak safety
//
// The `Submission` object can hold borrows of command buffers. In order for it to be safe to leak
// a `Submission`, the borrowed object themselves must be protected by a fence.
#[must_use]
pub struct Submission {
    fence: Arc<Fence>,      // TODO: make optional
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

impl Submission {
    /// Returns `true` if destroying this `Submission` object would block the CPU for some time.
    #[inline]
    pub fn destroying_would_block(&self) -> bool {
        !self.finished()
    }

    /// Returns `true` if the GPU has finished executing this submission.
    #[inline]
    pub fn finished(&self) -> bool {
        self.fence.ready().unwrap_or(false)     // TODO: what to do in case of error?
    }
}

impl Drop for Submission {
    fn drop(&mut self) {
        self.fence.wait(Duration::from_secs(10)).unwrap();      // TODO: handle some errors
    }
}

trait KeepAlive {}
impl<T> KeepAlive for T {}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) -> Submission {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits, keep_alive }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // TODO: for now we always create a Fence in order to put it in the submission
        let fence = fence.unwrap_or_else(|| Fence::new(queue.device().clone()));

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            //let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            let fence = fence.internal_object();
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }

        Submission {
            keep_alive: keep_alive,
            fence: fence,
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
            keep_alive: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let qf = device.physical_device().queue_family_by_id(queue_family).unwrap();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device.clone());
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        if !current_infos.pre_pipeline_barrier.is_empty() {
            let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, qf),
                                                         Kind::Primary::<EmptySinglePassRenderPass,
                                                                         EmptySinglePassRenderPass>,
                                                         Flags::OneTimeSubmit).unwrap();
            cb.pipeline_barrier(current_infos.pre_pipeline_barrier);
            new_submit.commandBufferCount += 1;
            infos.command_buffers.push(cb.internal_object());
            infos.keep_alive.push(Arc::new(cb) as Arc<_>);
        }

        infos.command_buffers.push(current.inner().internal_object());

        if !current_infos.post_pipeline_barrier.is_empty() {
            let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, qf),
                                                         Kind::Primary::<EmptySinglePassRenderPass,
                                                                         EmptySinglePassRenderPass>,
                                                         Flags::OneTimeSubmit).unwrap();
            cb.pipeline_barrier(current_infos.post_pipeline_barrier);
            new_submit.commandBufferCount += 1;
            infos.command_buffers.push(cb.internal_object());
            infos.keep_alive.push(Arc::new(cb) as Arc<_>);
        }

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            infos.keep_alive.push(semaphore);
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            infos.keep_alive.push(semaphore);
            new_submit.signalSemaphoreCount += 1;
        }

        infos.submits.push(new_submit);

        infos
    }
}
<|endoftext|>