<commit_before>//! Linear algebra utils module.
//!
//! Contains support methods for linear algebra structs.

use std::cmp;
use libnum::{Zero};
use std::ops::{Add, Mul, Sub, Div};

/// Compute dot product of two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::dot(&a,&b);
/// ```
pub fn dot<T: Copy + Zero + Add<T, Output=T> + Mul<T, Output=T>>(u: &[T], v: &[T]) -> T {
    let len = cmp::min(u.len(), v.len());
    let mut xs = &u[..len];
    let mut ys = &v[..len];

    let mut s = T::zero();
    let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
        (T::zero(), T::zero(), T::zero(), T::zero(),
            T::zero(), T::zero(), T::zero(), T::zero());

    while xs.len() >= 8 {
        p0 = p0 + xs[0] * ys[0];
        p1 = p1 + xs[1] * ys[1];
        p2 = p2 + xs[2] * ys[2];
        p3 = p3 + xs[3] * ys[3];
        p4 = p4 + xs[4] * ys[4];
        p5 = p5 + xs[5] * ys[5];
        p6 = p6 + xs[6] * ys[6];
        p7 = p7 + xs[7] * ys[7];

        xs = &xs[8..];
        ys = &ys[8..];
    }
    s = s + p0 + p4;
    s = s + p1 + p5;
    s = s + p2 + p6;
    s = s + p3 + p7;

    for i in 0..xs.len() {
        s = s + xs[i] * ys[i];
    }
    s
 }

/// Compute vector sum of two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::vec_sum(&a,&b);
///
/// assert_eq!(c, vec![2.0,4.0, 6.0, 8.0]);
/// ```
pub fn vec_sum<T: Copy + Zero + Add<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] + ys[i];
    }
    sum_data
}

/// Compute vector difference two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::vec_sub(&a,&b);
///
/// assert_eq!(c, vec![0.0; 4]);
/// ```
pub fn vec_sub<T: Copy + Zero + Sub<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] - ys[i];
    }
    sum_data
}

/// Computes elementwise multiplication.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::ele_mul(&a,&b);
///
/// assert_eq!(c, vec![1.0,4.0,9.0,16.0]);
/// ```
pub fn ele_mul<T: Copy + Zero + Mul<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] * ys[i];
    }
    sum_data
}

/// Computes elementwise division.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::ele_div(&a,&b);
///
/// assert_eq!(c, vec![1.0,4.0,9.0,16.0]);
/// ```
pub fn ele_div<T: Copy + Zero + Div<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] / ys[i];
    }
    sum_data
}

/// Find argmax of slice.
///
/// Returns index of first occuring maximum.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::argmax(&a);
/// assert_eq!(c, 3);
/// ```
pub fn argmax<T: Copy + PartialOrd>(u: &[T]) -> usize {
    assert!(u.len() != 0);

    let mut max_index = 0;
    let mut max = u[max_index];

    for (i, v) in (u.iter()).enumerate() {
        if max < *v {
            max_index = i;
            max = *v;
        }
    }

    max_index
}

/// Find index of value in slice.
///
/// Returns index of first occuring value.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::find(&a, 3.0);
/// assert_eq!(c, 2);
/// ```
pub fn find<T: PartialEq>(p: &[T], u: T) -> usize {
        for (i, v) in p.iter().enumerate() {
            if *v == u {
                return i;
            }
        }

        panic!("Value not found.")
    }<commit_msg>Fixing doc test error.<commit_after>//! Linear algebra utils module.
//!
//! Contains support methods for linear algebra structs.

use std::cmp;
use libnum::{Zero};
use std::ops::{Add, Mul, Sub, Div};

/// Compute dot product of two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::dot(&a,&b);
/// ```
pub fn dot<T: Copy + Zero + Add<T, Output=T> + Mul<T, Output=T>>(u: &[T], v: &[T]) -> T {
    let len = cmp::min(u.len(), v.len());
    let mut xs = &u[..len];
    let mut ys = &v[..len];

    let mut s = T::zero();
    let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
        (T::zero(), T::zero(), T::zero(), T::zero(),
            T::zero(), T::zero(), T::zero(), T::zero());

    while xs.len() >= 8 {
        p0 = p0 + xs[0] * ys[0];
        p1 = p1 + xs[1] * ys[1];
        p2 = p2 + xs[2] * ys[2];
        p3 = p3 + xs[3] * ys[3];
        p4 = p4 + xs[4] * ys[4];
        p5 = p5 + xs[5] * ys[5];
        p6 = p6 + xs[6] * ys[6];
        p7 = p7 + xs[7] * ys[7];

        xs = &xs[8..];
        ys = &ys[8..];
    }
    s = s + p0 + p4;
    s = s + p1 + p5;
    s = s + p2 + p6;
    s = s + p3 + p7;

    for i in 0..xs.len() {
        s = s + xs[i] * ys[i];
    }
    s
 }

/// Compute vector sum of two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::vec_sum(&a,&b);
///
/// assert_eq!(c, vec![2.0,4.0, 6.0, 8.0]);
/// ```
pub fn vec_sum<T: Copy + Zero + Add<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] + ys[i];
    }
    sum_data
}

/// Compute vector difference two slices.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::vec_sub(&a,&b);
///
/// assert_eq!(c, vec![0.0; 4]);
/// ```
pub fn vec_sub<T: Copy + Zero + Sub<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] - ys[i];
    }
    sum_data
}

/// Computes elementwise multiplication.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::ele_mul(&a,&b);
///
/// assert_eq!(c, vec![1.0,4.0,9.0,16.0]);
/// ```
pub fn ele_mul<T: Copy + Zero + Mul<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] * ys[i];
    }
    sum_data
}

/// Computes elementwise division.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
/// let b = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::ele_div(&a,&b);
///
/// assert_eq!(c, vec![1.0; 4]);
/// ```
pub fn ele_div<T: Copy + Zero + Div<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let xs = &u[..len];
    let ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];

    for i in 0..len {
        sum_data[i] = xs[i] / ys[i];
    }
    sum_data
}

/// Find argmax of slice.
///
/// Returns index of first occuring maximum.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::argmax(&a);
/// assert_eq!(c, 3);
/// ```
pub fn argmax<T: Copy + PartialOrd>(u: &[T]) -> usize {
    assert!(u.len() != 0);

    let mut max_index = 0;
    let mut max = u[max_index];

    for (i, v) in (u.iter()).enumerate() {
        if max < *v {
            max_index = i;
            max = *v;
        }
    }

    max_index
}

/// Find index of value in slice.
///
/// Returns index of first occuring value.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::utils;
/// let a = vec![1.0,2.0,3.0,4.0];
///
/// let c = utils::find(&a, 3.0);
/// assert_eq!(c, 2);
/// ```
pub fn find<T: PartialEq>(p: &[T], u: T) -> usize {
        for (i, v) in p.iter().enumerate() {
            if *v == u {
                return i;
            }
        }

        panic!("Value not found.")
    }<|endoftext|>


<commit_before>// Copyright 2017 Serde 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. This file may not be copied, modified, or distributed
// except according to those terms.

use internals::ast::{Container, Data, Style};
use internals::attr::{EnumTag, Identifier};
use internals::Ctxt;

/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
    check_getter(cx, cont);
    check_flatten(cx, cont);
    check_identifier(cx, cont);
    check_variant_skip_attrs(cx, cont);
    check_internal_tag_field_name_conflict(cx, cont);
    check_adjacent_tag_conflict(cx, cont);
}

/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(_) => {
            if cont.data.has_getter() {
                cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
            }
        }
        Data::Struct(_, _) => {
            if cont.data.has_getter() && cont.attrs.remote().is_none() {
                cx.error(
                    "#[serde(getter = \"...\")] can only be used in structs \
                     that have #[serde(remote = \"...\")]",
                );
            }
        }
    }
}

/// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(_) => {
            if cont.attrs.has_flatten() {
                cx.error("#[serde(flatten)] cannot be used within enums");
            }
        }
        Data::Struct(style, _) => {
            for field in cont.data.all_fields() {
                if !field.attrs.flatten() {
                    continue;
                }
                match style {
                    Style::Tuple => {
                        cx.error("#[serde(flatten)] cannot be used on tuple structs");
                    }
                    Style::Newtype => {
                        cx.error("#[serde(flatten)] cannot be used on newtype structs");
                    }
                    _ => {}
                }
                if field.attrs.skip_serializing() {
                    cx.error(
                        "#[serde(flatten] can not be combined with \
                         #[serde(skip_serializing)]",
                    );
                } else if field.attrs.skip_serializing_if().is_some() {
                    cx.error(
                        "#[serde(flatten] can not be combined with \
                         #[serde(skip_serializing_if = \"...\")]",
                    );
                } else if field.attrs.skip_deserializing() {
                    cx.error(
                        "#[serde(flatten] can not be combined with \
                         #[serde(skip_deserializing)]",
                    );
                }
            }
        }
    }
}

/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum that has the `field_identifier` attribute.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for (i, variant) in variants.iter().enumerate() {
        match (
            variant.style,
            cont.attrs.identifier(),
            variant.attrs.other(),
        ) {
            // The `other` attribute may only be used in a field_identifier.
            (_, Identifier::Variant, true) | (_, Identifier::No, true) => {
                cx.error("#[serde(other)] may only be used inside a field_identifier");
            }

            // Variant with `other` attribute must be the last one.
            (Style::Unit, Identifier::Field, true) => {
                if i < variants.len() - 1 {
                    cx.error("#[serde(other)] must be the last variant");
                }
            }

            // Variant with `other` attribute must be a unit variant.
            (_, Identifier::Field, true) => {
                cx.error("#[serde(other)] must be on a unit variant");
            }

            // Any sort of variant is allowed if this is not an identifier.
            (_, Identifier::No, false) => {}

            // Unit variant without `other` attribute is always fine.
            (Style::Unit, _, false) => {}

            // The last field is allowed to be a newtype catch-all.
            (Style::Newtype, Identifier::Field, false) => {
                if i < variants.len() - 1 {
                    cx.error(format!("`{}` must be the last variant", variant.ident));
                }
            }

            (_, Identifier::Field, false) => {
                cx.error("field_identifier may only contain unit variants");
            }

            (_, Identifier::Variant, false) => {
                cx.error("variant_identifier may only contain unit variants");
            }
        }
    }
}

/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for variant in variants.iter() {
        if variant.attrs.serialize_with().is_some() {
            if variant.attrs.skip_serializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(serialize_with)] and \
                     #[serde(skip_serializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                let ident = field
                    .ident
                    .as_ref()
                    .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                if field.attrs.skip_serializing() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing)]",
                        variant.ident, ident
                    ));
                }

                if field.attrs.skip_serializing_if().is_some() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing_if)]",
                        variant.ident, ident
                    ));
                }
            }
        }

        if variant.attrs.deserialize_with().is_some() {
            if variant.attrs.skip_deserializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(deserialize_with)] and \
                     #[serde(skip_deserializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                if field.attrs.skip_deserializing() {
                    let ident = field
                        .ident
                        .as_ref()
                        .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(deserialize_with)] \
                         and a field {} marked with #[serde(skip_deserializing)]",
                        variant.ident, ident
                    ));
                }
            }
        }
    }
}

/// The tag of an internally-tagged struct variant must not be
/// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => return,
    };

    let tag = match *cont.attrs.tag() {
        EnumTag::Internal { ref tag } => tag.as_str(),
        EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
    };

    let diagnose_conflict = || {
        let message = format!("variant field name `{}` conflicts with internal tag", tag);
        cx.error(message);
    };

    for variant in variants {
        match variant.style {
            Style::Struct => {
                for field in &variant.fields {
                    let check_ser = !field.attrs.skip_serializing();
                    let check_de = !field.attrs.skip_deserializing();
                    let name = field.attrs.name();
                    let ser_name = name.serialize_name();
                    let de_name = name.deserialize_name();

                    if check_ser && ser_name == tag || check_de && de_name == tag {
                        diagnose_conflict();
                        return;
                    }
                }
            }
            Style::Unit | Style::Newtype | Style::Tuple => {}
        }
    }
}

/// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
    let (type_tag, content_tag) = match *cont.attrs.tag() {
        EnumTag::Adjacent {
            ref tag,
            ref content,
        } => (tag, content),
        EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
    };

    if type_tag == content_tag {
        let message = format!(
            "enum tags `{}` for type and content conflict with each other",
            type_tag
        );
        cx.error(message);
    }
}
<commit_msg>Allow flatten attribute in enums<commit_after>// Copyright 2017 Serde 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. This file may not be copied, modified, or distributed
// except according to those terms.

use internals::ast::{Container, Data, Field, Style};
use internals::attr::{EnumTag, Identifier};
use internals::Ctxt;

/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
    check_getter(cx, cont);
    check_flatten(cx, cont);
    check_identifier(cx, cont);
    check_variant_skip_attrs(cx, cont);
    check_internal_tag_field_name_conflict(cx, cont);
    check_adjacent_tag_conflict(cx, cont);
}

/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(_) => {
            if cont.data.has_getter() {
                cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
            }
        }
        Data::Struct(_, _) => {
            if cont.data.has_getter() && cont.attrs.remote().is_none() {
                cx.error(
                    "#[serde(getter = \"...\")] can only be used in structs \
                     that have #[serde(remote = \"...\")]",
                );
            }
        }
    }
}

/// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(ref variants) => {
            for variant in variants {
                for field in &variant.fields {
                    check_flatten_field(cx, variant.style, field);
                }
            }
        }
        Data::Struct(style, ref fields) => {
            for field in fields {
                check_flatten_field(cx, style, field);
            }
        }
    }
}

fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
    if !field.attrs.flatten() {
        return;
    }
    match style {
        Style::Tuple => {
            cx.error("#[serde(flatten)] cannot be used on tuple structs");
        }
        Style::Newtype => {
            cx.error("#[serde(flatten)] cannot be used on newtype structs");
        }
        _ => {}
    }
    if field.attrs.skip_serializing() {
        cx.error(
            "#[serde(flatten] can not be combined with \
             #[serde(skip_serializing)]",
        );
    } else if field.attrs.skip_serializing_if().is_some() {
        cx.error(
            "#[serde(flatten] can not be combined with \
             #[serde(skip_serializing_if = \"...\")]",
        );
    } else if field.attrs.skip_deserializing() {
        cx.error(
            "#[serde(flatten] can not be combined with \
             #[serde(skip_deserializing)]",
        );
    }
}

/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum that has the `field_identifier` attribute.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for (i, variant) in variants.iter().enumerate() {
        match (
            variant.style,
            cont.attrs.identifier(),
            variant.attrs.other(),
        ) {
            // The `other` attribute may only be used in a field_identifier.
            (_, Identifier::Variant, true) | (_, Identifier::No, true) => {
                cx.error("#[serde(other)] may only be used inside a field_identifier");
            }

            // Variant with `other` attribute must be the last one.
            (Style::Unit, Identifier::Field, true) => {
                if i < variants.len() - 1 {
                    cx.error("#[serde(other)] must be the last variant");
                }
            }

            // Variant with `other` attribute must be a unit variant.
            (_, Identifier::Field, true) => {
                cx.error("#[serde(other)] must be on a unit variant");
            }

            // Any sort of variant is allowed if this is not an identifier.
            (_, Identifier::No, false) => {}

            // Unit variant without `other` attribute is always fine.
            (Style::Unit, _, false) => {}

            // The last field is allowed to be a newtype catch-all.
            (Style::Newtype, Identifier::Field, false) => {
                if i < variants.len() - 1 {
                    cx.error(format!("`{}` must be the last variant", variant.ident));
                }
            }

            (_, Identifier::Field, false) => {
                cx.error("field_identifier may only contain unit variants");
            }

            (_, Identifier::Variant, false) => {
                cx.error("variant_identifier may only contain unit variants");
            }
        }
    }
}

/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for variant in variants.iter() {
        if variant.attrs.serialize_with().is_some() {
            if variant.attrs.skip_serializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(serialize_with)] and \
                     #[serde(skip_serializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                let ident = field
                    .ident
                    .as_ref()
                    .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                if field.attrs.skip_serializing() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing)]",
                        variant.ident, ident
                    ));
                }

                if field.attrs.skip_serializing_if().is_some() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing_if)]",
                        variant.ident, ident
                    ));
                }
            }
        }

        if variant.attrs.deserialize_with().is_some() {
            if variant.attrs.skip_deserializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(deserialize_with)] and \
                     #[serde(skip_deserializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                if field.attrs.skip_deserializing() {
                    let ident = field
                        .ident
                        .as_ref()
                        .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(deserialize_with)] \
                         and a field {} marked with #[serde(skip_deserializing)]",
                        variant.ident, ident
                    ));
                }
            }
        }
    }
}

/// The tag of an internally-tagged struct variant must not be
/// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => return,
    };

    let tag = match *cont.attrs.tag() {
        EnumTag::Internal { ref tag } => tag.as_str(),
        EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
    };

    let diagnose_conflict = || {
        let message = format!("variant field name `{}` conflicts with internal tag", tag);
        cx.error(message);
    };

    for variant in variants {
        match variant.style {
            Style::Struct => {
                for field in &variant.fields {
                    let check_ser = !field.attrs.skip_serializing();
                    let check_de = !field.attrs.skip_deserializing();
                    let name = field.attrs.name();
                    let ser_name = name.serialize_name();
                    let de_name = name.deserialize_name();

                    if check_ser && ser_name == tag || check_de && de_name == tag {
                        diagnose_conflict();
                        return;
                    }
                }
            }
            Style::Unit | Style::Newtype | Style::Tuple => {}
        }
    }
}

/// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
    let (type_tag, content_tag) = match *cont.attrs.tag() {
        EnumTag::Adjacent {
            ref tag,
            ref content,
        } => (tag, content),
        EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
    };

    if type_tag == content_tag {
        let message = format!(
            "enum tags `{}` for type and content conflict with each other",
            type_tag
        );
        cx.error(message);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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 chrono::prelude::{DateTime, Utc};
use chrono::Duration;
use std::sync::Arc;

use crate::chain;
use crate::common::types::{Error, SyncState, SyncStatus};
use crate::core::core::hash::Hashed;
use crate::core::global;
use crate::p2p::{self, Peer};

/// Fast sync has 3 "states":
/// * syncing headers
/// * once all headers are sync'd, requesting the txhashset state
/// * once we have the state, get blocks after that
///
/// The StateSync struct implements and monitors the middle step.
pub struct StateSync {
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,

	prev_state_sync: Option<DateTime<Utc>>,
	state_sync_peer: Option<Arc<Peer>>,
}

impl StateSync {
	pub fn new(
		sync_state: Arc<SyncState>,
		peers: Arc<p2p::Peers>,
		chain: Arc<chain::Chain>,
	) -> StateSync {
		StateSync {
			sync_state,
			peers,
			chain,
			prev_state_sync: None,
			state_sync_peer: None,
		}
	}

	/// Check whether state sync should run and triggers a state download when
	/// it's time (we have all headers). Returns true as long as state sync
	/// needs monitoring, false when it's either done or turned off.
	pub fn check_run(
		&mut self,
		header_head: &chain::Tip,
		head: &chain::Tip,
		tail: &chain::Tip,
		highest_height: u64,
	) -> bool {
		trace!("state_sync: head.height: {}, tail.height: {}. header_head.height: {}, highest_height: {}",
			   head.height, tail.height, header_head.height, highest_height,
		);

		let mut sync_need_restart = false;

		// check sync error
		{
			let clone = self.sync_state.sync_error();
			if let Some(ref sync_error) = *clone.read() {
				error!("state_sync: error = {:?}. restart fast sync", sync_error);
				sync_need_restart = true;
			}
			drop(clone);
		}

		// check peer connection status of this sync
		if let Some(ref peer) = self.state_sync_peer {
			if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
				if !peer.is_connected() {
					sync_need_restart = true;
					info!(
						"state_sync: peer connection lost: {:?}. restart",
						peer.info.addr,
					);
				}
			}
		}

		// if txhashset downloaded and validated successfully, we switch to BodySync state,
		// and we need call state_sync_reset() to make it ready for next possible state sync.
		let done = if let SyncStatus::TxHashsetDone = self.sync_state.status() {
			self.sync_state.update(SyncStatus::BodySync {
				current_height: 0,
				highest_height: 0,
			});
			true
		} else {
			false
		};

		if sync_need_restart || done {
			self.state_sync_reset();
			self.sync_state.clear_sync_error();
		}

		if done {
			return false;
		}

		// run fast sync if applicable, normally only run one-time, except restart in error
		if header_head.height == highest_height {
			let (go, download_timeout) = self.state_sync_due();

			if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
				if download_timeout {
					error!("state_sync: TxHashsetDownload status timeout in 10 minutes!");
					self.sync_state
						.set_sync_error(Error::P2P(p2p::Error::Timeout));
				}
			}

			if go {
				self.state_sync_peer = None;
				match self.request_state(&header_head) {
					Ok(peer) => {
						self.state_sync_peer = Some(peer);
					}
					Err(e) => self.sync_state.set_sync_error(Error::P2P(e)),
				}

				// to avoid the confusing log,
				// update the final HeaderSync state mainly for 'current_height'
				{
					let status = self.sync_state.status();
					if let SyncStatus::HeaderSync { .. } = status {
						self.sync_state.update(SyncStatus::HeaderSync {
							current_height: header_head.height,
							highest_height,
						});
					}
				}

				self.sync_state.update(SyncStatus::TxHashsetDownload {
					start_time: Utc::now(),
					prev_update_time: Utc::now(),
					update_time: Utc::now(),
					prev_downloaded_size: 0,
					downloaded_size: 0,
					total_size: 0,
				});
			}
		}
		true
	}

	fn request_state(&self, header_head: &chain::Tip) -> Result<Arc<Peer>, p2p::Error> {
		let threshold = global::state_sync_threshold() as u64;

		if let Some(peer) = self.peers.most_work_peer() {
			// ask for txhashset at state_sync_threshold
			let mut txhashset_head = self
				.chain
				.get_block_header(&header_head.prev_block_h)
				.unwrap();
			for _ in 0..threshold {
				txhashset_head = self.chain.get_previous_header(&txhashset_head).unwrap();
			}
			let bhash = txhashset_head.hash();
			debug!(
				"state_sync: before txhashset request, header head: {} / {}, txhashset_head: {} / {}",
				header_head.height,
				header_head.last_block_h,
				txhashset_head.height,
				bhash
			);
			if let Err(e) = peer.send_txhashset_request(txhashset_head.height, bhash) {
				error!("state_sync: send_txhashset_request err! {:?}", e);
				return Err(e);
			}
			return Ok(peer.clone());
		}
		Err(p2p::Error::PeerException)
	}

	// For now this is a one-time thing (it can be slow) at initial startup.
	fn state_sync_due(&mut self) -> (bool, bool) {
		let now = Utc::now();
		let mut download_timeout = false;

		match self.prev_state_sync {
			None => {
				self.prev_state_sync = Some(now);
				(true, download_timeout)
			}
			Some(prev) => {
				if now - prev > Duration::minutes(10) {
					download_timeout = true;
				}
				(false, download_timeout)
			}
		}
	}

	fn state_sync_reset(&mut self) {
		self.prev_state_sync = None;
		self.state_sync_peer = None;
	}
}
<commit_msg>fix: the restart of state sync doesn't work sometimes (#2687)<commit_after>// Copyright 2018 The Grin Developers
//
// 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 chrono::prelude::{DateTime, Utc};
use chrono::Duration;
use std::sync::Arc;

use crate::chain;
use crate::common::types::{Error, SyncState, SyncStatus};
use crate::core::core::hash::Hashed;
use crate::core::global;
use crate::p2p::{self, Peer};

/// Fast sync has 3 "states":
/// * syncing headers
/// * once all headers are sync'd, requesting the txhashset state
/// * once we have the state, get blocks after that
///
/// The StateSync struct implements and monitors the middle step.
pub struct StateSync {
	sync_state: Arc<SyncState>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,

	prev_state_sync: Option<DateTime<Utc>>,
	state_sync_peer: Option<Arc<Peer>>,
}

impl StateSync {
	pub fn new(
		sync_state: Arc<SyncState>,
		peers: Arc<p2p::Peers>,
		chain: Arc<chain::Chain>,
	) -> StateSync {
		StateSync {
			sync_state,
			peers,
			chain,
			prev_state_sync: None,
			state_sync_peer: None,
		}
	}

	/// Check whether state sync should run and triggers a state download when
	/// it's time (we have all headers). Returns true as long as state sync
	/// needs monitoring, false when it's either done or turned off.
	pub fn check_run(
		&mut self,
		header_head: &chain::Tip,
		head: &chain::Tip,
		tail: &chain::Tip,
		highest_height: u64,
	) -> bool {
		trace!("state_sync: head.height: {}, tail.height: {}. header_head.height: {}, highest_height: {}",
			   head.height, tail.height, header_head.height, highest_height,
		);

		let mut sync_need_restart = false;

		// check sync error
		{
			let clone = self.sync_state.sync_error();
			if let Some(ref sync_error) = *clone.read() {
				error!("state_sync: error = {:?}. restart fast sync", sync_error);
				sync_need_restart = true;
			}
			drop(clone);
		}

		// check peer connection status of this sync
		if let Some(ref peer) = self.state_sync_peer {
			if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
				if !peer.is_connected() {
					sync_need_restart = true;
					info!(
						"state_sync: peer connection lost: {:?}. restart",
						peer.info.addr,
					);
				}
			}
		}

		// if txhashset downloaded and validated successfully, we switch to BodySync state,
		// and we need call state_sync_reset() to make it ready for next possible state sync.
		let done = if let SyncStatus::TxHashsetDone = self.sync_state.status() {
			self.sync_state.update(SyncStatus::BodySync {
				current_height: 0,
				highest_height: 0,
			});
			true
		} else {
			false
		};

		if sync_need_restart || done {
			self.state_sync_reset();
			self.sync_state.clear_sync_error();
		}

		if done {
			return false;
		}

		// run fast sync if applicable, normally only run one-time, except restart in error
		if sync_need_restart || header_head.height == highest_height {
			let (go, download_timeout) = self.state_sync_due();

			if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
				if download_timeout {
					error!("state_sync: TxHashsetDownload status timeout in 10 minutes!");
					self.sync_state
						.set_sync_error(Error::P2P(p2p::Error::Timeout));
				}
			}

			if go {
				self.state_sync_peer = None;
				match self.request_state(&header_head) {
					Ok(peer) => {
						self.state_sync_peer = Some(peer);
					}
					Err(e) => self.sync_state.set_sync_error(Error::P2P(e)),
				}

				// to avoid the confusing log,
				// update the final HeaderSync state mainly for 'current_height'
				{
					let status = self.sync_state.status();
					if let SyncStatus::HeaderSync { .. } = status {
						self.sync_state.update(SyncStatus::HeaderSync {
							current_height: header_head.height,
							highest_height,
						});
					}
				}

				self.sync_state.update(SyncStatus::TxHashsetDownload {
					start_time: Utc::now(),
					prev_update_time: Utc::now(),
					update_time: Utc::now(),
					prev_downloaded_size: 0,
					downloaded_size: 0,
					total_size: 0,
				});
			}
		}
		true
	}

	fn request_state(&self, header_head: &chain::Tip) -> Result<Arc<Peer>, p2p::Error> {
		let threshold = global::state_sync_threshold() as u64;

		if let Some(peer) = self.peers.most_work_peer() {
			// ask for txhashset at state_sync_threshold
			let mut txhashset_head = self
				.chain
				.get_block_header(&header_head.prev_block_h)
				.unwrap();
			for _ in 0..threshold {
				txhashset_head = self.chain.get_previous_header(&txhashset_head).unwrap();
			}
			let bhash = txhashset_head.hash();
			debug!(
				"state_sync: before txhashset request, header head: {} / {}, txhashset_head: {} / {}",
				header_head.height,
				header_head.last_block_h,
				txhashset_head.height,
				bhash
			);
			if let Err(e) = peer.send_txhashset_request(txhashset_head.height, bhash) {
				error!("state_sync: send_txhashset_request err! {:?}", e);
				return Err(e);
			}
			return Ok(peer.clone());
		}
		Err(p2p::Error::PeerException)
	}

	// For now this is a one-time thing (it can be slow) at initial startup.
	fn state_sync_due(&mut self) -> (bool, bool) {
		let now = Utc::now();
		let mut download_timeout = false;

		match self.prev_state_sync {
			None => {
				self.prev_state_sync = Some(now);
				(true, download_timeout)
			}
			Some(prev) => {
				if now - prev > Duration::minutes(10) {
					download_timeout = true;
				}
				(false, download_timeout)
			}
		}
	}

	fn state_sync_reset(&mut self) {
		self.prev_state_sync = None;
		self.state_sync_peer = None;
	}
}
<|endoftext|>


<commit_before><commit_msg>space: Handle multiple overlapping rects when merging damage<commit_after><|endoftext|>


<commit_before>//! These tests just check that the macros are available in libstd.

#![cfg_attr(
    any(
        all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
        all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
        all(target_arch = "powerpc", target_os = "linux"),
        all(target_arch = "powerpc64", target_os = "linux"),
        any(target_arch = "x86", target_arch = "x86_64"),
    ),
    feature(stdsimd)
)]

#[test]
#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
fn arm_linux() {
    println!("neon: {}", is_arm_feature_detected!("neon"));
    println!("pmull: {}", is_arm_feature_detected!("pmull"));
}

#[test]
#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
fn aarch64_linux() {
    println!("fp: {}", is_aarch64_feature_detected!("fp"));
    println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
    println!("neon: {}", is_aarch64_feature_detected!("neon"));
    println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
    println!("sve: {}", is_aarch64_feature_detected!("sve"));
    println!("crc: {}", is_aarch64_feature_detected!("crc"));
    println!("crypto: {}", is_aarch64_feature_detected!("crypto"));
    println!("lse: {}", is_aarch64_feature_detected!("lse"));
    println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
    println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
    println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
    println!("tme: {}", is_aarch64_feature_detected!("tme"));
}

#[test]
#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
fn powerpc_linux() {
    println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
    println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
    println!("power8: {}", is_powerpc_feature_detected!("power8"));
}

#[test]
#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
fn powerpc64_linux() {
    println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
    println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
    println!("power8: {}", is_powerpc64_feature_detected!("power8"));
}

#[test]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn x86_all() {
    // the below is in alphabetical order and matches
    // the order of X86_ALLOWED_FEATURES in rustc_codegen_ssa's target_features.rs

    println!("adx: {:?}", is_x86_feature_detected!("adx"));
    println!("aes: {:?}", is_x86_feature_detected!("aes"));
    println!("avx: {:?}", is_x86_feature_detected!("avx"));
    println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
    println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16"));
    println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg"));
    println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw"));
    println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd"));
    println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
    println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
    println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
    println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
    println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
    println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
    println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
    println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
    println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
    println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
    println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
    println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
    println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
    println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
    println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
    println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
    println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b"));
    println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
    println!("fma: {:?}", is_x86_feature_detected!("fma"));
    println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
    println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
    println!("movbe: {:?}", is_x86_feature_detected!("movbe"));
    println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
    println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
    println!("rdrand: {:?}", is_x86_feature_detected!("rdrand"));
    println!("rdseed: {:?}", is_x86_feature_detected!("rdseed"));
    println!("rtm: {:?}", is_x86_feature_detected!("rtm"));
    println!("sha: {:?}", is_x86_feature_detected!("sha"));
    println!("sse: {:?}", is_x86_feature_detected!("sse"));
    println!("sse2: {:?}", is_x86_feature_detected!("sse2"));
    println!("sse3: {:?}", is_x86_feature_detected!("sse3"));
    println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1"));
    println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2"));
    println!("sse4a: {:?}", is_x86_feature_detected!("sse4a"));
    println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
    println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
    println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
    println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
    println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
    println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
}
<commit_msg>Removed movbe from run-time-detect<commit_after>//! These tests just check that the macros are available in libstd.

#![cfg_attr(
    any(
        all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
        all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
        all(target_arch = "powerpc", target_os = "linux"),
        all(target_arch = "powerpc64", target_os = "linux"),
        any(target_arch = "x86", target_arch = "x86_64"),
    ),
    feature(stdsimd)
)]

#[test]
#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
fn arm_linux() {
    println!("neon: {}", is_arm_feature_detected!("neon"));
    println!("pmull: {}", is_arm_feature_detected!("pmull"));
}

#[test]
#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
fn aarch64_linux() {
    println!("fp: {}", is_aarch64_feature_detected!("fp"));
    println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
    println!("neon: {}", is_aarch64_feature_detected!("neon"));
    println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
    println!("sve: {}", is_aarch64_feature_detected!("sve"));
    println!("crc: {}", is_aarch64_feature_detected!("crc"));
    println!("crypto: {}", is_aarch64_feature_detected!("crypto"));
    println!("lse: {}", is_aarch64_feature_detected!("lse"));
    println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
    println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
    println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
    println!("tme: {}", is_aarch64_feature_detected!("tme"));
}

#[test]
#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
fn powerpc_linux() {
    println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
    println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
    println!("power8: {}", is_powerpc_feature_detected!("power8"));
}

#[test]
#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
fn powerpc64_linux() {
    println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
    println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
    println!("power8: {}", is_powerpc64_feature_detected!("power8"));
}

#[test]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn x86_all() {
    // the below is in alphabetical order and matches
    // the order of X86_ALLOWED_FEATURES in rustc_codegen_ssa's target_features.rs

    println!("adx: {:?}", is_x86_feature_detected!("adx"));
    println!("aes: {:?}", is_x86_feature_detected!("aes"));
    println!("avx: {:?}", is_x86_feature_detected!("avx"));
    println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
    println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16"));
    println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg"));
    println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw"));
    println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd"));
    println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
    println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
    println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
    println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
    println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
    println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
    println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
    println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
    println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
    println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
    println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
    println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
    println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
    println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
    println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
    println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
    println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b"));
    println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
    println!("fma: {:?}", is_x86_feature_detected!("fma"));
    println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
    println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
    //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature
    println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
    println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
    println!("rdrand: {:?}", is_x86_feature_detected!("rdrand"));
    println!("rdseed: {:?}", is_x86_feature_detected!("rdseed"));
    println!("rtm: {:?}", is_x86_feature_detected!("rtm"));
    println!("sha: {:?}", is_x86_feature_detected!("sha"));
    println!("sse: {:?}", is_x86_feature_detected!("sse"));
    println!("sse2: {:?}", is_x86_feature_detected!("sse2"));
    println!("sse3: {:?}", is_x86_feature_detected!("sse3"));
    println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1"));
    println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2"));
    println!("sse4a: {:?}", is_x86_feature_detected!("sse4a"));
    println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
    println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
    println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
    println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
    println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
    println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
}
<|endoftext|>


<commit_before>//! Creation of ar archives like for the lib and staticlib crate type

use std::collections::BTreeMap;
use std::fs::File;
use std::path::{Path, PathBuf};

use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::METADATA_FILENAME;
use rustc_session::Session;

use object::{Object, ObjectSymbol, SymbolKind};

#[derive(Debug)]
enum ArchiveEntry {
    FromArchive { archive_index: usize, entry_index: usize },
    File(PathBuf),
}

pub(crate) struct ArArchiveBuilder<'a> {
    sess: &'a Session,
    dst: PathBuf,
    lib_search_paths: Vec<PathBuf>,
    use_gnu_style_archive: bool,
    no_builtin_ranlib: bool,

    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
    // the end of an archive for linkers to not get confused.
    entries: Vec<(String, ArchiveEntry)>,
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
        use rustc_codegen_ssa::back::link::archive_search_paths;

        let (src_archives, entries) = if let Some(input) = input {
            let mut archive = ar::Archive::new(File::open(input).unwrap());
            let mut entries = Vec::new();

            let mut i = 0;
            while let Some(entry) = archive.next_entry() {
                let entry = entry.unwrap();
                entries.push((
                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
                    ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
                ));
                i += 1;
            }

            (vec![(input.to_owned(), archive)], entries)
        } else {
            (vec![], Vec::new())
        };

        ArArchiveBuilder {
            sess,
            dst: output.to_path_buf(),
            lib_search_paths: archive_search_paths(sess),
            use_gnu_style_archive: sess.target.archive_format == "gnu",
            // FIXME fix builtin ranlib on macOS
            no_builtin_ranlib: sess.target.is_like_osx,

            src_archives,
            entries,
        }
    }

    fn src_files(&mut self) -> Vec<String> {
        self.entries.iter().map(|(name, _)| name.clone()).collect()
    }

    fn remove_file(&mut self, name: &str) {
        let index = self
            .entries
            .iter()
            .position(|(entry_name, _)| entry_name == name)
            .expect("Tried to remove file not existing in src archive");
        self.entries.remove(index);
    }

    fn add_file(&mut self, file: &Path) {
        self.entries.push((
            file.file_name().unwrap().to_str().unwrap().to_string(),
            ArchiveEntry::File(file.to_owned()),
        ));
    }

    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
        let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
        self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
            panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
        });
    }

    fn add_rlib(
        &mut self,
        rlib: &Path,
        name: &str,
        lto: bool,
        skip_objects: bool,
    ) -> std::io::Result<()> {
        let obj_start = name.to_owned();

        self.add_archive(rlib.to_owned(), move |fname: &str| {
            // Ignore metadata files, no matter the name.
            if fname == METADATA_FILENAME {
                return true;
            }

            // Don't include Rust objects if LTO is enabled
            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
                return true;
            }

            // Otherwise if this is *not* a rust object and we're skipping
            // objects then skip this file
            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
                return true;
            }

            // ok, don't skip this
            false
        })
    }

    fn update_symbols(&mut self) {}

    fn build(mut self) {
        enum BuilderKind {
            Bsd(ar::Builder<File>),
            Gnu(ar::GnuBuilder<File>),
        }

        let sess = self.sess;

        let mut symbol_table = BTreeMap::new();

        let mut entries = Vec::new();

        for (entry_name, entry) in self.entries {
            // FIXME only read the symbol table of the object files to avoid having to keep all
            // object files in memory at once, or read them twice.
            let data = match entry {
                ArchiveEntry::FromArchive { archive_index, entry_index } => {
                    // FIXME read symbols from symtab
                    use std::io::Read;
                    let (ref _src_archive_path, ref mut src_archive) =
                        self.src_archives[archive_index];
                    let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
                    let mut data = Vec::new();
                    entry.read_to_end(&mut data).unwrap();
                    data
                }
                ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
                    sess.fatal(&format!(
                        "error while reading object file during archive building: {}",
                        err
                    ));
                }),
            };

            if !self.no_builtin_ranlib {
                match object::File::parse(&*data) {
                    Ok(object) => {
                        symbol_table.insert(
                            entry_name.as_bytes().to_vec(),
                            object
                                .symbols()
                                .filter_map(|symbol| {
                                    if symbol.is_undefined()
                                        || symbol.is_local()
                                        || symbol.kind() != SymbolKind::Data
                                            && symbol.kind() != SymbolKind::Text
                                            && symbol.kind() != SymbolKind::Tls
                                    {
                                        None
                                    } else {
                                        symbol.name().map(|name| name.as_bytes().to_vec()).ok()
                                    }
                                })
                                .collect::<Vec<_>>(),
                        );
                    }
                    Err(err) => {
                        let err = err.to_string();
                        if err == "Unknown file magic" {
                            // Not an object file; skip it.
                        } else {
                            sess.fatal(&format!(
                                "error parsing `{}` during archive creation: {}",
                                entry_name, err
                            ));
                        }
                    }
                }
            }

            entries.push((entry_name, data));
        }

        let mut builder = if self.use_gnu_style_archive {
            BuilderKind::Gnu(
                ar::GnuBuilder::new(
                    File::create(&self.dst).unwrap_or_else(|err| {
                        sess.fatal(&format!(
                            "error opening destination during archive building: {}",
                            err
                        ));
                    }),
                    entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
                    ar::GnuSymbolTableFormat::Size32,
                    symbol_table,
                )
                .unwrap(),
            )
        } else {
            BuilderKind::Bsd(
                ar::Builder::new(
                    File::create(&self.dst).unwrap_or_else(|err| {
                        sess.fatal(&format!(
                            "error opening destination during archive building: {}",
                            err
                        ));
                    }),
                    symbol_table,
                )
                .unwrap(),
            )
        };

        // Add all files
        for (entry_name, data) in entries.into_iter() {
            let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
            match builder {
                BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
                BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
            }
        }

        // Finalize archive
        std::mem::drop(builder);

        if self.no_builtin_ranlib {
            let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib");

            // Run ranlib to be able to link the archive
            let status = std::process::Command::new(ranlib)
                .arg(self.dst)
                .status()
                .expect("Couldn't run ranlib");

            if !status.success() {
                self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
            }
        }
    }

    fn inject_dll_import_lib(
        &mut self,
        _lib_name: &str,
        _dll_imports: &[rustc_middle::middle::cstore::DllImport],
        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
    ) {
        bug!("injecting dll imports is not supported");
    }
}

impl<'a> ArArchiveBuilder<'a> {
    fn add_archive<F>(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Result<()>
    where
        F: FnMut(&str) -> bool + 'static,
    {
        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
        let archive_index = self.src_archives.len();

        let mut i = 0;
        while let Some(entry) = archive.next_entry() {
            let entry = entry?;
            let file_name = String::from_utf8(entry.header().identifier().to_vec())
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
            if !skip(&file_name) {
                self.entries
                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
            }
            i += 1;
        }

        self.src_archives.push((archive_path, archive));
        Ok(())
    }
}
<commit_msg>Use the object crate for archive reading during archive building<commit_after>//! Creation of ar archives like for the lib and staticlib crate type

use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, Read, Seek};
use std::path::{Path, PathBuf};

use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::METADATA_FILENAME;
use rustc_session::Session;

use object::read::archive::ArchiveFile;
use object::{Object, ObjectSymbol, ReadCache, SymbolKind};

#[derive(Debug)]
enum ArchiveEntry {
    FromArchive { archive_index: usize, file_range: (u64, u64) },
    File(PathBuf),
}

pub(crate) struct ArArchiveBuilder<'a> {
    sess: &'a Session,
    dst: PathBuf,
    lib_search_paths: Vec<PathBuf>,
    use_gnu_style_archive: bool,
    no_builtin_ranlib: bool,

    src_archives: Vec<File>,
    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
    // the end of an archive for linkers to not get confused.
    entries: Vec<(String, ArchiveEntry)>,
}

impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
        use rustc_codegen_ssa::back::link::archive_search_paths;

        let (src_archives, entries) = if let Some(input) = input {
            let read_cache = ReadCache::new(File::open(input).unwrap());
            let archive = ArchiveFile::parse(&read_cache).unwrap();
            let mut entries = Vec::new();

            for entry in archive.members() {
                let entry = entry.unwrap();
                entries.push((
                    String::from_utf8(entry.name().to_vec()).unwrap(),
                    ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
                ));
            }

            (vec![read_cache.into_inner()], entries)
        } else {
            (vec![], Vec::new())
        };

        ArArchiveBuilder {
            sess,
            dst: output.to_path_buf(),
            lib_search_paths: archive_search_paths(sess),
            use_gnu_style_archive: sess.target.archive_format == "gnu",
            // FIXME fix builtin ranlib on macOS
            no_builtin_ranlib: sess.target.is_like_osx,

            src_archives,
            entries,
        }
    }

    fn src_files(&mut self) -> Vec<String> {
        self.entries.iter().map(|(name, _)| name.clone()).collect()
    }

    fn remove_file(&mut self, name: &str) {
        let index = self
            .entries
            .iter()
            .position(|(entry_name, _)| entry_name == name)
            .expect("Tried to remove file not existing in src archive");
        self.entries.remove(index);
    }

    fn add_file(&mut self, file: &Path) {
        self.entries.push((
            file.file_name().unwrap().to_str().unwrap().to_string(),
            ArchiveEntry::File(file.to_owned()),
        ));
    }

    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
        let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
        self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
            panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
        });
    }

    fn add_rlib(
        &mut self,
        rlib: &Path,
        name: &str,
        lto: bool,
        skip_objects: bool,
    ) -> io::Result<()> {
        let obj_start = name.to_owned();

        self.add_archive(rlib.to_owned(), move |fname: &str| {
            // Ignore metadata files, no matter the name.
            if fname == METADATA_FILENAME {
                return true;
            }

            // Don't include Rust objects if LTO is enabled
            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
                return true;
            }

            // Otherwise if this is *not* a rust object and we're skipping
            // objects then skip this file
            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
                return true;
            }

            // ok, don't skip this
            false
        })
    }

    fn update_symbols(&mut self) {}

    fn build(mut self) {
        enum BuilderKind {
            Bsd(ar::Builder<File>),
            Gnu(ar::GnuBuilder<File>),
        }

        let sess = self.sess;

        let mut symbol_table = BTreeMap::new();

        let mut entries = Vec::new();

        for (entry_name, entry) in self.entries {
            // FIXME only read the symbol table of the object files to avoid having to keep all
            // object files in memory at once, or read them twice.
            let data = match entry {
                ArchiveEntry::FromArchive { archive_index, file_range } => {
                    // FIXME read symbols from symtab
                    let src_read_cache = &mut self.src_archives[archive_index];

                    src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
                    let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
                    src_read_cache.read_exact(&mut data).unwrap();

                    data
                }
                ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
                    sess.fatal(&format!(
                        "error while reading object file during archive building: {}",
                        err
                    ));
                }),
            };

            if !self.no_builtin_ranlib {
                match object::File::parse(&*data) {
                    Ok(object) => {
                        symbol_table.insert(
                            entry_name.as_bytes().to_vec(),
                            object
                                .symbols()
                                .filter_map(|symbol| {
                                    if symbol.is_undefined()
                                        || symbol.is_local()
                                        || symbol.kind() != SymbolKind::Data
                                            && symbol.kind() != SymbolKind::Text
                                            && symbol.kind() != SymbolKind::Tls
                                    {
                                        None
                                    } else {
                                        symbol.name().map(|name| name.as_bytes().to_vec()).ok()
                                    }
                                })
                                .collect::<Vec<_>>(),
                        );
                    }
                    Err(err) => {
                        let err = err.to_string();
                        if err == "Unknown file magic" {
                            // Not an object file; skip it.
                        } else {
                            sess.fatal(&format!(
                                "error parsing `{}` during archive creation: {}",
                                entry_name, err
                            ));
                        }
                    }
                }
            }

            entries.push((entry_name, data));
        }

        let mut builder = if self.use_gnu_style_archive {
            BuilderKind::Gnu(
                ar::GnuBuilder::new(
                    File::create(&self.dst).unwrap_or_else(|err| {
                        sess.fatal(&format!(
                            "error opening destination during archive building: {}",
                            err
                        ));
                    }),
                    entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
                    ar::GnuSymbolTableFormat::Size32,
                    symbol_table,
                )
                .unwrap(),
            )
        } else {
            BuilderKind::Bsd(
                ar::Builder::new(
                    File::create(&self.dst).unwrap_or_else(|err| {
                        sess.fatal(&format!(
                            "error opening destination during archive building: {}",
                            err
                        ));
                    }),
                    symbol_table,
                )
                .unwrap(),
            )
        };

        // Add all files
        for (entry_name, data) in entries.into_iter() {
            let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
            match builder {
                BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
                BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
            }
        }

        // Finalize archive
        std::mem::drop(builder);

        if self.no_builtin_ranlib {
            let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib");

            // Run ranlib to be able to link the archive
            let status = std::process::Command::new(ranlib)
                .arg(self.dst)
                .status()
                .expect("Couldn't run ranlib");

            if !status.success() {
                self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
            }
        }
    }

    fn inject_dll_import_lib(
        &mut self,
        _lib_name: &str,
        _dll_imports: &[rustc_middle::middle::cstore::DllImport],
        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
    ) {
        bug!("injecting dll imports is not supported");
    }
}

impl<'a> ArArchiveBuilder<'a> {
    fn add_archive<F>(&mut self, archive_path: PathBuf, mut skip: F) -> io::Result<()>
    where
        F: FnMut(&str) -> bool + 'static,
    {
        let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
        let archive = ArchiveFile::parse(&read_cache).unwrap();
        let archive_index = self.src_archives.len();

        for entry in archive.members() {
            let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
            let file_name = String::from_utf8(entry.name().to_vec())
                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
            if !skip(&file_name) {
                self.entries.push((
                    file_name,
                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
                ));
            }
        }

        self.src_archives.push(read_cache.into_inner());
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::{generate::*, norm::Norm, types::*};
use ndarray::*;

#[derive(Debug, Clone)]
pub struct MGS<A> {
    dim: usize,
    q: Vec<Array1<A>>,
    r: Vec<Array1<A>>,
}

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dim: usize) -> Self {
        Self {
            dim,
            q: Vec::new(),
            r: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dim
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> A::Real
    where
        S: Data<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut a = a.into_owned();
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = a.dot(q);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        self.r.push(coef);
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        nrm
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }

    /// Get each vector norm and coefficients as R matrix
    pub fn get_r(&self) -> Array2<A> {
        let len = self.len();
        let mut r = Array2::zeros((len, len));
        for i in 0..len {
            for j in 0..=i {
                r[(j, i)] = self.r[i][j];
            }
        }
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::assert::*;
    use rand::{distributions::Standard, prelude::*};

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    fn test<A: Scalar + Lapack>(rtol: A::Real)
    where
        Standard: Distribution<A>,
    {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, rtol).unwrap();

        dbg!(q.t().dot(&q));
        close_l2(&q.t().dot(&q), &Array2::eye(3), rtol).unwrap();
    }

    #[test]
    fn test_f32() {
        test::<f32>(1e-5);
    }

    #[test]
    fn test_c32() {
        test::<c32>(1e-5);
    }
}
<commit_msg>Drop rand restriction (#143)<commit_after>use crate::{generate::*, norm::Norm, types::*};
use ndarray::*;

#[derive(Debug, Clone)]
pub struct MGS<A> {
    dim: usize,
    q: Vec<Array1<A>>,
    r: Vec<Array1<A>>,
}

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dim: usize) -> Self {
        Self {
            dim,
            q: Vec::new(),
            r: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dim
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> A::Real
    where
        S: Data<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut a = a.into_owned();
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = a.dot(q);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        self.r.push(coef);
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        nrm
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }

    /// Get each vector norm and coefficients as R matrix
    pub fn get_r(&self) -> Array2<A> {
        let len = self.len();
        let mut r = Array2::zeros((len, len));
        for i in 0..len {
            for j in 0..=i {
                r[(j, i)] = self.r[i][j];
            }
        }
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::assert::*;

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    fn test<A: Scalar + Lapack>(rtol: A::Real) {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, rtol).unwrap();

        dbg!(q.t().dot(&q));
        close_l2(&q.t().dot(&q), &Array2::eye(3), rtol).unwrap();
    }

    #[test]
    fn test_f32() {
        test::<f32>(1e-5);
    }

    #[test]
    fn test_c32() {
        test::<c32>(1e-5);
    }
}
<|endoftext|>


<commit_before>use docopt::{self, Docopt, ArgvMap};

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision list [--filter <text>] [--expires-in-days <days>] [<directory>]

Options:
  -h --help     Show this help message.
  --version     Show version.
";

pub fn parse_args(args: Vec<&str>) -> Result<ArgvMap, docopt::Error> {
    Docopt::new(USAGE).and_then(|docopt| {
        docopt.argv(args).version(Some(format!("mprovision {}", version!()))).parse()
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use expectest::prelude::*;

    #[test]
    fn list_command() {
        expect!(parse_args(vec!["mprovision", "list"])).to(be_ok());
        expect!(parse_args(vec!["mprovision", "list", "."])).to(be_ok());
        expect!(parse_args(vec!["mprovision", "list", "--filter abc"])).to(be_ok());
        expect!(parse_args(vec!["mprovision", "list", "--filter abc", "."])).to(be_ok());
        expect!(parse_args(vec!["mprovision", "list", "--expires-in-days 0"])).to(be_ok());
        expect!(parse_args(vec!["mprovision", "list", "--expires-in-days 0", "."])).to(be_ok());
    }
}
<commit_msg>Make parse to accept IntoIterator<commit_after>use docopt::{self, Docopt, ArgvMap};

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision list [--filter <text>] [--expires-in-days <days>] [<directory>]

Options:
  -h --help     Show this help message.
  --version     Show version.
";

pub fn parse<I, S>(args: I) -> Result<ArgvMap, docopt::Error>
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    Docopt::new(USAGE).and_then(|docopt| {
        docopt.argv(args).version(Some(format!("mprovision {}", version!()))).parse()
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use expectest::prelude::*;

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "."])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--filter abc"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--filter abc", "."])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0", "."])).to(be_ok());
    }
}
<|endoftext|>


<commit_before>

// https://github.com/rust-lang/getopts
extern crate getopts;

extern crate libc;

// Rust FFI for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

pub struct Krb5Context {
    ctx: krb5::krb5_context,
}
impl Krb5Context {
    pub fn new() -> Option<Krb5Context> {
        let mut ctx: krb5::krb5_context = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_init_context(&mut ctx);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while initializing krb5")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as i64, detail);
                return None;
            }
        }
        Some(Krb5Context { ctx: ctx, })
    }
}

pub struct Krb5Cache {
    cache: krb5::krb5_ccache,
}
impl Krb5Cache {
    pub fn get(ctx: &Krb5Context) -> Option<Krb5Cache> {
        let mut cache: krb5::krb5_ccache = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_cc_default(ctx.ctx, &mut cache);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while getting default ccache")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as i64, detail);
                return None;
            }
        }
        Some(Krb5Cache { cache: cache, })
    }
}

pub struct Krb5Princ {
    princ: krb5::krb5_principal,
}
impl Krb5Princ {
    pub fn get(ctx: &Krb5Context, cache: &Krb5Cache) -> Option<Krb5Princ> {
        let mut princ: krb5::krb5_principal = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_cc_get_principal(ctx.ctx,
                                                   cache.cache,
                                                   &mut princ);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while retrieving principal name")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as i64, detail);
                return None;
            }
        }
        Some(Krb5Princ { princ: princ, })
    }
    pub fn realm(&self) -> String {
        let kp = unsafe { *self.princ };
        let d = kp.realm.data;
        let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
        s.into_owned()
    }
    pub fn data(&self) -> String {
        let kp = unsafe { *self.princ };
        let len = kp.length;

        // Pointer offset arithmetic
        // C code is: krb5_principal->(data+(i))->data
        (0..len).map(
            |i|
            unsafe{
                CStr::from_ptr((*kp.data.offset(i as isize)).data)
                    .to_string_lossy()
            })
            .collect::<Vec<_>>()
            .join("/")
    }
}

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let k5ctx = Krb5Context::new().unwrap();
    let k5cache = Krb5Cache::get(&k5ctx).unwrap();
    let k5princ = Krb5Princ::get(&k5ctx, &k5cache).unwrap();

    println!("{}", k5princ.data());
}
<commit_msg>Choose a better cast for com_err code (safe for 32bit/64bit)<commit_after>

// https://github.com/rust-lang/getopts
extern crate getopts;

extern crate libc;

// Rust FFI for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

pub struct Krb5Context {
    ctx: krb5::krb5_context,
}
impl Krb5Context {
    pub fn new() -> Option<Krb5Context> {
        let mut ctx: krb5::krb5_context = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_init_context(&mut ctx);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while initializing krb5")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as libc::c_long, detail);
                return None;
            }
        }
        Some(Krb5Context { ctx: ctx, })
    }
}

pub struct Krb5Cache {
    cache: krb5::krb5_ccache,
}
impl Krb5Cache {
    pub fn get(ctx: &Krb5Context) -> Option<Krb5Cache> {
        let mut cache: krb5::krb5_ccache = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_cc_default(ctx.ctx, &mut cache);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while getting default ccache")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as libc::c_long, detail);
                return None;
            }
        }
        Some(Krb5Cache { cache: cache, })
    }
}

pub struct Krb5Princ {
    princ: krb5::krb5_principal,
}
impl Krb5Princ {
    pub fn get(ctx: &Krb5Context, cache: &Krb5Cache) -> Option<Krb5Princ> {
        let mut princ: krb5::krb5_principal = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_cc_get_principal(ctx.ctx,
                                                   cache.cache,
                                                   &mut princ);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while retrieving principal name")
                    .unwrap().into_raw();
                com_err::com_err(whoami, code as libc::c_long, detail);
                return None;
            }
        }
        Some(Krb5Princ { princ: princ, })
    }
    pub fn realm(&self) -> String {
        let kp = unsafe { *self.princ };
        let d = kp.realm.data;
        let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
        s.into_owned()
    }
    pub fn data(&self) -> String {
        let kp = unsafe { *self.princ };
        let len = kp.length;

        // Pointer offset arithmetic
        // C code is: krb5_principal->(data+(i))->data
        (0..len).map(
            |i|
            unsafe{
                CStr::from_ptr((*kp.data.offset(i as isize)).data)
                    .to_string_lossy()
            })
            .collect::<Vec<_>>()
            .join("/")
    }
}

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let k5ctx = Krb5Context::new().unwrap();
    let k5cache = Krb5Cache::get(&k5ctx).unwrap();
    let k5princ = Krb5Princ::get(&k5ctx, &k5cache).unwrap();

    println!("{}", k5princ.data());
}
<|endoftext|>