<commit_before>use std::cmp;

use crate::ich::StableHashingContext;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{
    builtin::{self, FORBIDDEN_LINT_GROUPS},
    FutureIncompatibilityReason, Level, Lint, LintId,
};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
pub enum LintLevelSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),

    /// Lint level was set by a command-line flag.
    /// The provided `Level` is the level specified on the command line.
    /// (The actual level may be lower due to `--cap-lints`.)
    CommandLine(Symbol, Level),
}

impl LintLevelSource {
    pub fn name(&self) -> Symbol {
        match *self {
            LintLevelSource::Default => symbol::kw::Default,
            LintLevelSource::Node(name, _, _) => name,
            LintLevelSource::CommandLine(name, _) => name,
        }
    }

    pub fn span(&self) -> Span {
        match *self {
            LintLevelSource::Default => DUMMY_SP,
            LintLevelSource::Node(_, span, _) => span,
            LintLevelSource::CommandLine(_, _) => DUMMY_SP,
        }
    }
}

/// A tuple of a lint level and its source.
pub type LevelAndSource = (Level, LintLevelSource);

#[derive(Debug)]
pub struct LintLevelSets {
    pub list: Vec<LintSet>,
    pub lint_cap: Level,
}

#[derive(Debug)]
pub enum LintSet {
    CommandLine {
        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
        // flag.
        specs: FxHashMap<LintId, LevelAndSource>,
    },

    Node {
        specs: FxHashMap<LintId, LevelAndSource>,
        parent: u32,
    },
}

impl LintLevelSets {
    pub fn new() -> Self {
        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
    }

    pub fn get_lint_level(
        &self,
        lint: &'static Lint,
        idx: u32,
        aux: Option<&FxHashMap<LintId, LevelAndSource>>,
        sess: &Session,
    ) -> LevelAndSource {
        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);

        // If `level` is none then we actually assume the default level for this
        // lint.
        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));

        // If we're about to issue a warning, check at the last minute for any
        // directives against the warnings "lint". If, for example, there's an
        // `allow(warnings)` in scope then we want to respect that instead.
        //
        // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
        // triggers in cases (like #80988) where you have `forbid(warnings)`,
        // and so if we turned that into an error, it'd defeat the purpose of the
        // future compatibility warning.
        if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) {
            let (warnings_level, warnings_src) =
                self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
            if let Some(configured_warning_level) = warnings_level {
                if configured_warning_level != Level::Warn {
                    level = configured_warning_level;
                    src = warnings_src;
                }
            }
        }

        // Ensure that we never exceed the `--cap-lints` argument.
        level = cmp::min(level, self.lint_cap);

        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
            // Ensure that we never exceed driver level.
            level = cmp::min(*driver_level, level);
        }

        (level, src)
    }

    pub fn get_lint_id_level(
        &self,
        id: LintId,
        mut idx: u32,
        aux: Option<&FxHashMap<LintId, LevelAndSource>>,
    ) -> (Option<Level>, LintLevelSource) {
        if let Some(specs) = aux {
            if let Some(&(level, src)) = specs.get(&id) {
                return (Some(level), src);
            }
        }
        loop {
            match self.list[idx as usize] {
                LintSet::CommandLine { ref specs } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    return (None, LintLevelSource::Default);
                }
                LintSet::Node { ref specs, parent } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    idx = parent;
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct LintLevelMap {
    pub sets: LintLevelSets,
    pub id_to_set: FxHashMap<HirId, u32>,
}

impl LintLevelMap {
    /// If the `id` was previously registered with `register_id` when building
    /// this `LintLevelMap` this returns the corresponding lint level and source
    /// of the lint level for the lint provided.
    ///
    /// If the `id` was not previously registered, returns `None`. If `None` is
    /// returned then the parent of `id` should be acquired and this function
    /// should be called again.
    pub fn level_and_source(
        &self,
        lint: &'static Lint,
        id: HirId,
        session: &Session,
    ) -> Option<LevelAndSource> {
        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let LintLevelMap { ref sets, ref id_to_set } = *self;

        id_to_set.hash_stable(hcx, hasher);

        let LintLevelSets { ref list, lint_cap } = *sets;

        lint_cap.hash_stable(hcx, hasher);

        hcx.while_hashing_spans(true, |hcx| {
            list.len().hash_stable(hcx, hasher);

            // We are working under the assumption here that the list of
            // lint-sets is built in a deterministic order.
            for lint_set in list {
                ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);

                match *lint_set {
                    LintSet::CommandLine { ref specs } => {
                        specs.hash_stable(hcx, hasher);
                    }
                    LintSet::Node { ref specs, parent } => {
                        specs.hash_stable(hcx, hasher);
                        parent.hash_stable(hcx, hasher);
                    }
                }
            }
        })
    }
}

pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>);

impl<'a> LintDiagnosticBuilder<'a> {
    /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
    pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
        self.0.set_primary_message(msg);
        self.0
    }

    /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
    pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> {
        LintDiagnosticBuilder(err)
    }
}

pub fn struct_lint_level<'s, 'd>(
    sess: &'s Session,
    lint: &'static Lint,
    level: Level,
    src: LintLevelSource,
    span: Option<MultiSpan>,
    decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
) {
    // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
    // the "real" work.
    fn struct_lint_level_impl(
        sess: &'s Session,
        lint: &'static Lint,
        level: Level,
        src: LintLevelSource,
        span: Option<MultiSpan>,
        decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
    ) {
        // Check for future incompatibility lints and issue a stronger warning.
        let lint_id = LintId::of(lint);
        let future_incompatible = lint.future_incompatible;

        let has_future_breakage =
            future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());

        let mut err = match (level, span) {
            (Level::Allow, span) => {
                if has_future_breakage {
                    if let Some(span) = span {
                        sess.struct_span_allow(span, "")
                    } else {
                        sess.struct_allow("")
                    }
                } else {
                    return;
                }
            }
            (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
            (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
            (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
            (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
        };

        // If this code originates in a foreign macro, aka something that this crate
        // did not itself author, then it's likely that there's nothing this crate
        // can do about it. We probably want to skip the lint entirely.
        if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
            // Any suggestions made here are likely to be incorrect, so anything we
            // emit shouldn't be automatically fixed by rustfix.
            err.allow_suggestions(false);

            // If this is a future incompatible that is not an edition fixing lint
            // it'll become a hard error, so we have to emit *something*. Also,
            // if this lint occurs in the expansion of a macro from an external crate,
            // allow individual lints to opt-out from being reported.
            let not_future_incompatible =
                future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true);
            if not_future_incompatible && !lint.report_in_external_macro {
                err.cancel();
                // Don't continue further, since we don't want to have
                // `diag_span_note_once` called for a diagnostic that isn't emitted.
                return;
            }
        }

        let name = lint.name_lower();
        match src {
            LintLevelSource::Default => {
                sess.diag_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    &format!("`#[{}({})]` on by default", level.as_str(), name),
                );
            }
            LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
                let flag = match orig_level {
                    Level::Warn => "-W",
                    Level::Deny => "-D",
                    Level::Forbid => "-F",
                    Level::Allow => "-A",
                    Level::ForceWarn => "--force-warns",
                };
                let hyphen_case_lint_name = name.replace("_", "-");
                if lint_flag_val.as_str() == name {
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "requested on the command line with `{} {}`",
                            flag, hyphen_case_lint_name
                        ),
                    );
                } else {
                    let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`{} {}` implied by `{} {}`",
                            flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
                        ),
                    );
                }
            }
            LintLevelSource::Node(lint_attr_name, src, reason) => {
                if let Some(rationale) = reason {
                    err.note(&rationale.as_str());
                }
                sess.diag_span_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    src,
                    "the lint level is defined here",
                );
                if lint_attr_name.as_str() != name {
                    let level_str = level.as_str();
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`#[{}({})]` implied by `#[{}({})]`",
                            level_str, name, level_str, lint_attr_name
                        ),
                    );
                }
            }
        }

        err.code(DiagnosticId::Lint { name, has_future_breakage });

        if let Some(future_incompatible) = future_incompatible {
            let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
                "once this associated item is added to the standard library, the ambiguity may \
                 cause an error or change in behavior!"
                    .to_owned()
            } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
                "this borrowing pattern was not meant to be accepted, and may become a hard error \
                 in the future"
                    .to_owned()
            } else if let FutureIncompatibilityReason::EditionError(edition) =
                future_incompatible.reason
            {
                let current_edition = sess.edition();
                format!(
                    "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
                    current_edition, edition
                )
            } else if let FutureIncompatibilityReason::EditionSemanticsChange(edition) =
                future_incompatible.reason
            {
                format!("this changes meaning in Rust {}", edition)
            } else {
                "this was previously accepted by the compiler but is being phased out; \
                 it will become a hard error in a future release!"
                    .to_owned()
            };
            if future_incompatible.explain_reason {
                err.warn(&explanation);
            }
            if !future_incompatible.reference.is_empty() {
                let citation =
                    format!("for more information, see {}", future_incompatible.reference);
                err.note(&citation);
            }
        }

        // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
        decorate(LintDiagnosticBuilder::new(err));
    }
    struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
}

/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
    let expn_data = span.ctxt().outer_expn_data();
    match expn_data.kind {
        ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => {
            false
        }
        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
        ExpnKind::Macro { kind: MacroKind::Bang, name: _, proc_macro: _ } => {
            // Dummy span for the `def_site` means it's an external macro.
            expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
        }
        ExpnKind::Macro { .. } => true, // definitely a plugin
    }
}
<commit_msg>Use the macro to implement HashStable.<commit_after>use std::cmp;

use crate::ich::StableHashingContext;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{
    builtin::{self, FORBIDDEN_LINT_GROUPS},
    FutureIncompatibilityReason, Level, Lint, LintId,
};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};

/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
pub enum LintLevelSource {
    /// Lint is at the default level as declared
    /// in rustc or a plugin.
    Default,

    /// Lint level was set by an attribute.
    Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),

    /// Lint level was set by a command-line flag.
    /// The provided `Level` is the level specified on the command line.
    /// (The actual level may be lower due to `--cap-lints`.)
    CommandLine(Symbol, Level),
}

impl LintLevelSource {
    pub fn name(&self) -> Symbol {
        match *self {
            LintLevelSource::Default => symbol::kw::Default,
            LintLevelSource::Node(name, _, _) => name,
            LintLevelSource::CommandLine(name, _) => name,
        }
    }

    pub fn span(&self) -> Span {
        match *self {
            LintLevelSource::Default => DUMMY_SP,
            LintLevelSource::Node(_, span, _) => span,
            LintLevelSource::CommandLine(_, _) => DUMMY_SP,
        }
    }
}

/// A tuple of a lint level and its source.
pub type LevelAndSource = (Level, LintLevelSource);

#[derive(Debug, HashStable)]
pub struct LintLevelSets {
    pub list: Vec<LintSet>,
    pub lint_cap: Level,
}

#[derive(Debug, HashStable)]
pub enum LintSet {
    CommandLine {
        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
        // flag.
        specs: FxHashMap<LintId, LevelAndSource>,
    },

    Node {
        specs: FxHashMap<LintId, LevelAndSource>,
        parent: u32,
    },
}

impl LintLevelSets {
    pub fn new() -> Self {
        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
    }

    pub fn get_lint_level(
        &self,
        lint: &'static Lint,
        idx: u32,
        aux: Option<&FxHashMap<LintId, LevelAndSource>>,
        sess: &Session,
    ) -> LevelAndSource {
        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);

        // If `level` is none then we actually assume the default level for this
        // lint.
        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));

        // If we're about to issue a warning, check at the last minute for any
        // directives against the warnings "lint". If, for example, there's an
        // `allow(warnings)` in scope then we want to respect that instead.
        //
        // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
        // triggers in cases (like #80988) where you have `forbid(warnings)`,
        // and so if we turned that into an error, it'd defeat the purpose of the
        // future compatibility warning.
        if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) {
            let (warnings_level, warnings_src) =
                self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
            if let Some(configured_warning_level) = warnings_level {
                if configured_warning_level != Level::Warn {
                    level = configured_warning_level;
                    src = warnings_src;
                }
            }
        }

        // Ensure that we never exceed the `--cap-lints` argument.
        level = cmp::min(level, self.lint_cap);

        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
            // Ensure that we never exceed driver level.
            level = cmp::min(*driver_level, level);
        }

        (level, src)
    }

    pub fn get_lint_id_level(
        &self,
        id: LintId,
        mut idx: u32,
        aux: Option<&FxHashMap<LintId, LevelAndSource>>,
    ) -> (Option<Level>, LintLevelSource) {
        if let Some(specs) = aux {
            if let Some(&(level, src)) = specs.get(&id) {
                return (Some(level), src);
            }
        }
        loop {
            match self.list[idx as usize] {
                LintSet::CommandLine { ref specs } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    return (None, LintLevelSource::Default);
                }
                LintSet::Node { ref specs, parent } => {
                    if let Some(&(level, src)) = specs.get(&id) {
                        return (Some(level), src);
                    }
                    idx = parent;
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct LintLevelMap {
    pub sets: LintLevelSets,
    pub id_to_set: FxHashMap<HirId, u32>,
}

impl LintLevelMap {
    /// If the `id` was previously registered with `register_id` when building
    /// this `LintLevelMap` this returns the corresponding lint level and source
    /// of the lint level for the lint provided.
    ///
    /// If the `id` was not previously registered, returns `None`. If `None` is
    /// returned then the parent of `id` should be acquired and this function
    /// should be called again.
    pub fn level_and_source(
        &self,
        lint: &'static Lint,
        id: HirId,
        session: &Session,
    ) -> Option<LevelAndSource> {
        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
    #[inline]
    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
        let LintLevelMap { ref sets, ref id_to_set } = *self;

        id_to_set.hash_stable(hcx, hasher);

        hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher))
    }
}

pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>);

impl<'a> LintDiagnosticBuilder<'a> {
    /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
    pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
        self.0.set_primary_message(msg);
        self.0
    }

    /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder.
    pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> {
        LintDiagnosticBuilder(err)
    }
}

pub fn struct_lint_level<'s, 'd>(
    sess: &'s Session,
    lint: &'static Lint,
    level: Level,
    src: LintLevelSource,
    span: Option<MultiSpan>,
    decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd,
) {
    // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
    // the "real" work.
    fn struct_lint_level_impl(
        sess: &'s Session,
        lint: &'static Lint,
        level: Level,
        src: LintLevelSource,
        span: Option<MultiSpan>,
        decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>,
    ) {
        // Check for future incompatibility lints and issue a stronger warning.
        let lint_id = LintId::of(lint);
        let future_incompatible = lint.future_incompatible;

        let has_future_breakage =
            future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some());

        let mut err = match (level, span) {
            (Level::Allow, span) => {
                if has_future_breakage {
                    if let Some(span) = span {
                        sess.struct_span_allow(span, "")
                    } else {
                        sess.struct_allow("")
                    }
                } else {
                    return;
                }
            }
            (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
            (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
            (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
            (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
        };

        // If this code originates in a foreign macro, aka something that this crate
        // did not itself author, then it's likely that there's nothing this crate
        // can do about it. We probably want to skip the lint entirely.
        if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
            // Any suggestions made here are likely to be incorrect, so anything we
            // emit shouldn't be automatically fixed by rustfix.
            err.allow_suggestions(false);

            // If this is a future incompatible that is not an edition fixing lint
            // it'll become a hard error, so we have to emit *something*. Also,
            // if this lint occurs in the expansion of a macro from an external crate,
            // allow individual lints to opt-out from being reported.
            let not_future_incompatible =
                future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true);
            if not_future_incompatible && !lint.report_in_external_macro {
                err.cancel();
                // Don't continue further, since we don't want to have
                // `diag_span_note_once` called for a diagnostic that isn't emitted.
                return;
            }
        }

        let name = lint.name_lower();
        match src {
            LintLevelSource::Default => {
                sess.diag_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    &format!("`#[{}({})]` on by default", level.as_str(), name),
                );
            }
            LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
                let flag = match orig_level {
                    Level::Warn => "-W",
                    Level::Deny => "-D",
                    Level::Forbid => "-F",
                    Level::Allow => "-A",
                    Level::ForceWarn => "--force-warns",
                };
                let hyphen_case_lint_name = name.replace("_", "-");
                if lint_flag_val.as_str() == name {
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "requested on the command line with `{} {}`",
                            flag, hyphen_case_lint_name
                        ),
                    );
                } else {
                    let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`{} {}` implied by `{} {}`",
                            flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
                        ),
                    );
                }
            }
            LintLevelSource::Node(lint_attr_name, src, reason) => {
                if let Some(rationale) = reason {
                    err.note(&rationale.as_str());
                }
                sess.diag_span_note_once(
                    &mut err,
                    DiagnosticMessageId::from(lint),
                    src,
                    "the lint level is defined here",
                );
                if lint_attr_name.as_str() != name {
                    let level_str = level.as_str();
                    sess.diag_note_once(
                        &mut err,
                        DiagnosticMessageId::from(lint),
                        &format!(
                            "`#[{}({})]` implied by `#[{}({})]`",
                            level_str, name, level_str, lint_attr_name
                        ),
                    );
                }
            }
        }

        err.code(DiagnosticId::Lint { name, has_future_breakage });

        if let Some(future_incompatible) = future_incompatible {
            let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
                "once this associated item is added to the standard library, the ambiguity may \
                 cause an error or change in behavior!"
                    .to_owned()
            } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
                "this borrowing pattern was not meant to be accepted, and may become a hard error \
                 in the future"
                    .to_owned()
            } else if let FutureIncompatibilityReason::EditionError(edition) =
                future_incompatible.reason
            {
                let current_edition = sess.edition();
                format!(
                    "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
                    current_edition, edition
                )
            } else if let FutureIncompatibilityReason::EditionSemanticsChange(edition) =
                future_incompatible.reason
            {
                format!("this changes meaning in Rust {}", edition)
            } else {
                "this was previously accepted by the compiler but is being phased out; \
                 it will become a hard error in a future release!"
                    .to_owned()
            };
            if future_incompatible.explain_reason {
                err.warn(&explanation);
            }
            if !future_incompatible.reference.is_empty() {
                let citation =
                    format!("for more information, see {}", future_incompatible.reference);
                err.note(&citation);
            }
        }

        // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
        decorate(LintDiagnosticBuilder::new(err));
    }
    struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
}

/// Returns whether `span` originates in a foreign crate's external macro.
///
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
    let expn_data = span.ctxt().outer_expn_data();
    match expn_data.kind {
        ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => {
            false
        }
        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
        ExpnKind::Macro { kind: MacroKind::Bang, name: _, proc_macro: _ } => {
            // Dummy span for the `def_site` means it's an external macro.
            expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
        }
        ExpnKind::Macro { .. } => true, // definitely a plugin
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate num_derive;
#[macro_use]
extern crate serde;

pub mod resources;

use crossbeam_channel::{Receiver, Sender};
use ipc_channel::ipc::IpcSender;
use keyboard_types::KeyboardEvent;
use msg::constellation_msg::{InputMethodType, PipelineId, TopLevelBrowsingContextId};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
use webrender_api::{DeviceIntPoint, DeviceIntSize};

/// A cursor for the window. This is different from a CSS cursor (see
/// `CursorKind`) in that it has no `Auto` value.
#[repr(u8)]
#[derive(Clone, Copy, Deserialize, Eq, FromPrimitive, PartialEq, Serialize)]
pub enum Cursor {
    None,
    Default,
    Pointer,
    ContextMenu,
    Help,
    Progress,
    Wait,
    Cell,
    Crosshair,
    Text,
    VerticalText,
    Alias,
    Copy,
    Move,
    NoDrop,
    NotAllowed,
    Grab,
    Grabbing,
    EResize,
    NResize,
    NeResize,
    NwResize,
    SResize,
    SeResize,
    SwResize,
    WResize,
    EwResize,
    NsResize,
    NeswResize,
    NwseResize,
    ColResize,
    RowResize,
    AllScroll,
    ZoomIn,
    ZoomOut,
}

/// Used to wake up the event loop, provided by the servo port/embedder.
pub trait EventLoopWaker: 'static + Send {
    fn clone(&self) -> Box<EventLoopWaker + Send>;
    fn wake(&self);
}

/// Sends messages to the embedder.
pub struct EmbedderProxy {
    pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
    pub event_loop_waker: Box<EventLoopWaker>,
}

impl EmbedderProxy {
    pub fn send(&self, msg: (Option<TopLevelBrowsingContextId>, EmbedderMsg)) {
        // Send a message and kick the OS event loop awake.
        if let Err(err) = self.sender.send(msg) {
            warn!("Failed to send response ({:?}).", err);
        }
        self.event_loop_waker.wake();
    }
}

impl Clone for EmbedderProxy {
    fn clone(&self) -> EmbedderProxy {
        EmbedderProxy {
            sender: self.sender.clone(),
            event_loop_waker: self.event_loop_waker.clone(),
        }
    }
}

/// The port that the embedder receives messages on.
pub struct EmbedderReceiver {
    pub receiver: Receiver<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
}

impl EmbedderReceiver {
    pub fn try_recv_embedder_msg(
        &mut self,
    ) -> Option<(Option<TopLevelBrowsingContextId>, EmbedderMsg)> {
        self.receiver.try_recv().ok()
    }
    pub fn recv_embedder_msg(&mut self) -> (Option<TopLevelBrowsingContextId>, EmbedderMsg) {
        self.receiver.recv().unwrap()
    }
}

#[derive(Deserialize, Serialize)]
pub enum EmbedderMsg {
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Alerts the embedder that the current page has changed its title.
    ChangePageTitle(Option<String>),
    /// Move the window to a point
    MoveTo(DeviceIntPoint),
    /// Resize the window to size
    ResizeTo(DeviceIntSize),
    // Show an alert message.
    Alert(String, IpcSender<()>),
    /// Wether or not to allow a pipeline to load a url.
    AllowNavigationRequest(PipelineId, ServoUrl),
    /// Whether or not to allow script to open a new tab/browser
    AllowOpeningBrowser(IpcSender<bool>),
    /// A new browser was created by script
    BrowserCreated(TopLevelBrowsingContextId),
    /// Wether or not to unload a document
    AllowUnload(IpcSender<bool>),
    /// Sends an unconsumed key event back to the embedder.
    Keyboard(KeyboardEvent),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// A favicon was detected
    NewFavicon(ServoUrl),
    /// <head> tag finished parsing
    HeadParsed,
    /// The history state has changed.
    HistoryChanged(Vec<ServoUrl>, usize),
    /// Enter or exit fullscreen
    SetFullscreenState(bool),
    /// The load of a page has begun
    LoadStart,
    /// The load of a page has completed
    LoadComplete,
    /// A browser is to be closed
    CloseBrowser,
    /// A pipeline panicked. First string is the reason, second one is the backtrace.
    Panic(String, Option<String>),
    /// Open dialog to select bluetooth device.
    GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
    /// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
    SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
    /// Request to present an IME to the user when an editable element is focused.
    ShowIME(InputMethodType),
    /// Request to hide the IME when the editable element is blurred.
    HideIME,
    /// Servo has shut down
    Shutdown,
    /// Report a complete sampled profile
    ReportProfile(Vec<u8>),
}

impl Debug for EmbedderMsg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            EmbedderMsg::Status(..) => write!(f, "Status"),
            EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
            EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
            EmbedderMsg::Alert(..) => write!(f, "Alert"),
            EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
            EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
            EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
            EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
            EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
            EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
            EmbedderMsg::CloseBrowser => write!(f, "CloseBrowser"),
            EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"),
            EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
            EmbedderMsg::LoadStart => write!(f, "LoadStart"),
            EmbedderMsg::LoadComplete => write!(f, "LoadComplete"),
            EmbedderMsg::Panic(..) => write!(f, "Panic"),
            EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"),
            EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"),
            EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"),
            EmbedderMsg::HideIME => write!(f, "HideIME"),
            EmbedderMsg::Shutdown => write!(f, "Shutdown"),
            EmbedderMsg::AllowOpeningBrowser(..) => write!(f, "AllowOpeningBrowser"),
            EmbedderMsg::BrowserCreated(..) => write!(f, "BrowserCreated"),
            EmbedderMsg::ReportProfile(..) => write!(f, "ReportProfile"),
        }
    }
}

/// Filter for file selection;
/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".")
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct FilterPattern(pub String);
<commit_msg>Add Embbedder messages for setting/getting clipboard contents<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 https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate num_derive;
#[macro_use]
extern crate serde;

pub mod resources;

use crossbeam_channel::{Receiver, Sender};
use ipc_channel::ipc::IpcSender;
use keyboard_types::KeyboardEvent;
use msg::constellation_msg::{InputMethodType, PipelineId, TopLevelBrowsingContextId};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
use webrender_api::{DeviceIntPoint, DeviceIntSize};

/// A cursor for the window. This is different from a CSS cursor (see
/// `CursorKind`) in that it has no `Auto` value.
#[repr(u8)]
#[derive(Clone, Copy, Deserialize, Eq, FromPrimitive, PartialEq, Serialize)]
pub enum Cursor {
    None,
    Default,
    Pointer,
    ContextMenu,
    Help,
    Progress,
    Wait,
    Cell,
    Crosshair,
    Text,
    VerticalText,
    Alias,
    Copy,
    Move,
    NoDrop,
    NotAllowed,
    Grab,
    Grabbing,
    EResize,
    NResize,
    NeResize,
    NwResize,
    SResize,
    SeResize,
    SwResize,
    WResize,
    EwResize,
    NsResize,
    NeswResize,
    NwseResize,
    ColResize,
    RowResize,
    AllScroll,
    ZoomIn,
    ZoomOut,
}

/// Used to wake up the event loop, provided by the servo port/embedder.
pub trait EventLoopWaker: 'static + Send {
    fn clone(&self) -> Box<EventLoopWaker + Send>;
    fn wake(&self);
}

/// Sends messages to the embedder.
pub struct EmbedderProxy {
    pub sender: Sender<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
    pub event_loop_waker: Box<EventLoopWaker>,
}

impl EmbedderProxy {
    pub fn send(&self, msg: (Option<TopLevelBrowsingContextId>, EmbedderMsg)) {
        // Send a message and kick the OS event loop awake.
        if let Err(err) = self.sender.send(msg) {
            warn!("Failed to send response ({:?}).", err);
        }
        self.event_loop_waker.wake();
    }
}

impl Clone for EmbedderProxy {
    fn clone(&self) -> EmbedderProxy {
        EmbedderProxy {
            sender: self.sender.clone(),
            event_loop_waker: self.event_loop_waker.clone(),
        }
    }
}

/// The port that the embedder receives messages on.
pub struct EmbedderReceiver {
    pub receiver: Receiver<(Option<TopLevelBrowsingContextId>, EmbedderMsg)>,
}

impl EmbedderReceiver {
    pub fn try_recv_embedder_msg(
        &mut self,
    ) -> Option<(Option<TopLevelBrowsingContextId>, EmbedderMsg)> {
        self.receiver.try_recv().ok()
    }
    pub fn recv_embedder_msg(&mut self) -> (Option<TopLevelBrowsingContextId>, EmbedderMsg) {
        self.receiver.recv().unwrap()
    }
}

#[derive(Deserialize, Serialize)]
pub enum EmbedderMsg {
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Alerts the embedder that the current page has changed its title.
    ChangePageTitle(Option<String>),
    /// Move the window to a point
    MoveTo(DeviceIntPoint),
    /// Resize the window to size
    ResizeTo(DeviceIntSize),
    // Show an alert message.
    Alert(String, IpcSender<()>),
    /// Wether or not to allow a pipeline to load a url.
    AllowNavigationRequest(PipelineId, ServoUrl),
    /// Whether or not to allow script to open a new tab/browser
    AllowOpeningBrowser(IpcSender<bool>),
    /// A new browser was created by script
    BrowserCreated(TopLevelBrowsingContextId),
    /// Wether or not to unload a document
    AllowUnload(IpcSender<bool>),
    /// Sends an unconsumed key event back to the embedder.
    Keyboard(KeyboardEvent),
    /// Gets system clipboard contents
    GetClipboardContents(IpcSender<String>),
    /// Sets system clipboard contents
    SetClipboardContents(String),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// A favicon was detected
    NewFavicon(ServoUrl),
    /// <head> tag finished parsing
    HeadParsed,
    /// The history state has changed.
    HistoryChanged(Vec<ServoUrl>, usize),
    /// Enter or exit fullscreen
    SetFullscreenState(bool),
    /// The load of a page has begun
    LoadStart,
    /// The load of a page has completed
    LoadComplete,
    /// A browser is to be closed
    CloseBrowser,
    /// A pipeline panicked. First string is the reason, second one is the backtrace.
    Panic(String, Option<String>),
    /// Open dialog to select bluetooth device.
    GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
    /// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
    SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
    /// Request to present an IME to the user when an editable element is focused.
    ShowIME(InputMethodType),
    /// Request to hide the IME when the editable element is blurred.
    HideIME,
    /// Servo has shut down
    Shutdown,
    /// Report a complete sampled profile
    ReportProfile(Vec<u8>),
}

impl Debug for EmbedderMsg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            EmbedderMsg::Status(..) => write!(f, "Status"),
            EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"),
            EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
            EmbedderMsg::Alert(..) => write!(f, "Alert"),
            EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
            EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
            EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
            EmbedderMsg::GetClipboardContents(..) => write!(f, "GetClipboardContents"),
            EmbedderMsg::SetClipboardContents(..) => write!(f, "SetClipboardContents"),
            EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
            EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
            EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
            EmbedderMsg::CloseBrowser => write!(f, "CloseBrowser"),
            EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"),
            EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"),
            EmbedderMsg::LoadStart => write!(f, "LoadStart"),
            EmbedderMsg::LoadComplete => write!(f, "LoadComplete"),
            EmbedderMsg::Panic(..) => write!(f, "Panic"),
            EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"),
            EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"),
            EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"),
            EmbedderMsg::HideIME => write!(f, "HideIME"),
            EmbedderMsg::Shutdown => write!(f, "Shutdown"),
            EmbedderMsg::AllowOpeningBrowser(..) => write!(f, "AllowOpeningBrowser"),
            EmbedderMsg::BrowserCreated(..) => write!(f, "BrowserCreated"),
            EmbedderMsg::ReportProfile(..) => write!(f, "ReportProfile"),
        }
    }
}

/// Filter for file selection;
/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".")
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct FilterPattern(pub String);
<|endoftext|>


<commit_before>//! `i686`'s Streaming SIMD Extensions 4a (`SSE4a`)

use crate::{
    core_arch::{simd::*, x86::*},
    mem::transmute,
};

#[cfg(test)]
use stdsimd_test::assert_instr;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse4a.extrq"]
    fn extrq(x: i64x2, y: i8x16) -> i64x2;
    #[link_name = "llvm.x86.sse4a.insertq"]
    fn insertq(x: i64x2, y: i64x2) -> i64x2;
    #[link_name = "llvm.x86.sse4a.movnt.sd"]
    fn movntsd(x: *mut f64, y: __m128d);
    #[link_name = "llvm.x86.sse4a.movnt.ss"]
    fn movntss(x: *mut f32, y: __m128);
}

// FIXME(blocked on #248): _mm_extracti_si64(x, len, idx) // EXTRQ
// FIXME(blocked on #248): _mm_inserti_si64(x, y, len, idx) // INSERTQ

/// Extracts the bit range specified by `y` from the lower 64 bits of `x`.
///
/// The `[13:8]` bits of `y` specify the index of the bit-range to extract. The
/// `[5:0]` bits of `y` specify the length of the bit-range to extract. All
/// other bits are ignored.
///
/// If the length is zero, it is interpreted as `64`. If the length and index
/// are zero, the lower 64 bits of `x` are extracted.
///
/// If `length == 0 && index > 0` or `lenght + index > 64` the result is
/// undefined.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(extrq))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_extract_si64(x: __m128i, y: __m128i) -> __m128i {
    transmute(extrq(x.as_i64x2(), y.as_i8x16()))
}

/// Inserts the `[length:0]` bits of `y` into `x` at `index`.
///
/// The bits of `y`:
///
/// - `[69:64]` specify the `length`,
/// - `[77:72]` specify the index.
///
/// If the `length` is zero it is interpreted as `64`. If `index + length > 64`
/// or `index > 0 && length == 0` the result is undefined.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(insertq))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_insert_si64(x: __m128i, y: __m128i) -> __m128i {
    transmute(insertq(x.as_i64x2(), y.as_i64x2()))
}

/// Non-temporal store of `a.0` into `p`.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(movntsd))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_stream_sd(p: *mut f64, a: __m128d) {
    movntsd(p, a);
}

/// Non-temporal store of `a.0` into `p`.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(movntss))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_stream_ss(p: *mut f32, a: __m128) {
    movntss(p, a);
}

#[cfg(test)]
mod tests {
    use crate::core_arch::x86::*;
    use stdsimd_test::simd_test;

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_extract_si64() {
        let b = 0b0110_0000_0000_i64;
        //        ^^^^ bit range extracted
        let x = _mm_setr_epi64x(b, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = _mm_setr_epi64x(v, 0);
        let e = _mm_setr_epi64x(0b0110_i64, 0);
        let r = _mm_extract_si64(x, y);
        assert_eq_m128i(r, e);
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_insert_si64() {
        let i = 0b0110_i64;
        //        ^^^^ bit range inserted
        let z = 0b1010_1010_1010i64;
        //        ^^^^ bit range replaced
        let e = 0b0110_1010_1010i64;
        //        ^^^^ replaced 1010 with 0110
        let x = _mm_setr_epi64x(z, 0);
        let expected = _mm_setr_epi64x(e, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = _mm_setr_epi64x(i, v);
        let r = _mm_insert_si64(x, y);
        assert_eq_m128i(r, expected);
    }

    #[repr(align(16))]
    struct MemoryF64 {
        data: [f64; 2],
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_stream_sd() {
        let mut mem = MemoryF64 {
            data: [1.0_f64, 2.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = _mm_setr_pd(3.0, 4.0);

            _mm_stream_sd(d, x);
        }
        assert_eq!(mem.data[0], 3.0);
        assert_eq!(mem.data[1], 2.0);
    }

    #[repr(align(16))]
    struct MemoryF32 {
        data: [f32; 4],
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_stream_ss() {
        let mut mem = MemoryF32 {
            data: [1.0_f32, 2.0, 3.0, 4.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = _mm_setr_ps(5.0, 6.0, 7.0, 8.0);

            _mm_stream_ss(d, x);
        }
        assert_eq!(mem.data[0], 5.0);
        assert_eq!(mem.data[1], 2.0);
        assert_eq!(mem.data[2], 3.0);
        assert_eq!(mem.data[3], 4.0);
    }
}
<commit_msg>Improve docs of SSE4a stream intrinsics<commit_after>//! `i686`'s Streaming SIMD Extensions 4a (`SSE4a`)

use crate::{
    core_arch::{simd::*, x86::*},
    mem::transmute,
};

#[cfg(test)]
use stdsimd_test::assert_instr;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse4a.extrq"]
    fn extrq(x: i64x2, y: i8x16) -> i64x2;
    #[link_name = "llvm.x86.sse4a.insertq"]
    fn insertq(x: i64x2, y: i64x2) -> i64x2;
    #[link_name = "llvm.x86.sse4a.movnt.sd"]
    fn movntsd(x: *mut f64, y: __m128d);
    #[link_name = "llvm.x86.sse4a.movnt.ss"]
    fn movntss(x: *mut f32, y: __m128);
}

// FIXME(blocked on #248): _mm_extracti_si64(x, len, idx) // EXTRQ
// FIXME(blocked on #248): _mm_inserti_si64(x, y, len, idx) // INSERTQ

/// Extracts the bit range specified by `y` from the lower 64 bits of `x`.
///
/// The `[13:8]` bits of `y` specify the index of the bit-range to extract. The
/// `[5:0]` bits of `y` specify the length of the bit-range to extract. All
/// other bits are ignored.
///
/// If the length is zero, it is interpreted as `64`. If the length and index
/// are zero, the lower 64 bits of `x` are extracted.
///
/// If `length == 0 && index > 0` or `lenght + index > 64` the result is
/// undefined.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(extrq))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_extract_si64(x: __m128i, y: __m128i) -> __m128i {
    transmute(extrq(x.as_i64x2(), y.as_i8x16()))
}

/// Inserts the `[length:0]` bits of `y` into `x` at `index`.
///
/// The bits of `y`:
///
/// - `[69:64]` specify the `length`,
/// - `[77:72]` specify the index.
///
/// If the `length` is zero it is interpreted as `64`. If `index + length > 64`
/// or `index > 0 && length == 0` the result is undefined.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(insertq))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_insert_si64(x: __m128i, y: __m128i) -> __m128i {
    transmute(insertq(x.as_i64x2(), y.as_i64x2()))
}

/// Non-temporal store of `a.0` into `p`.
///
/// Writes 64-bit data to a memory location without polluting the caches.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(movntsd))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_stream_sd(p: *mut f64, a: __m128d) {
    movntsd(p, a);
}

/// Non-temporal store of `a.0` into `p`.
///
/// Writes 32-bit data to a memory location without polluting the caches.
#[inline]
#[target_feature(enable = "sse4a")]
#[cfg_attr(test, assert_instr(movntss))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _mm_stream_ss(p: *mut f32, a: __m128) {
    movntss(p, a);
}

#[cfg(test)]
mod tests {
    use crate::core_arch::x86::*;
    use stdsimd_test::simd_test;

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_extract_si64() {
        let b = 0b0110_0000_0000_i64;
        //        ^^^^ bit range extracted
        let x = _mm_setr_epi64x(b, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = _mm_setr_epi64x(v, 0);
        let e = _mm_setr_epi64x(0b0110_i64, 0);
        let r = _mm_extract_si64(x, y);
        assert_eq_m128i(r, e);
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_insert_si64() {
        let i = 0b0110_i64;
        //        ^^^^ bit range inserted
        let z = 0b1010_1010_1010i64;
        //        ^^^^ bit range replaced
        let e = 0b0110_1010_1010i64;
        //        ^^^^ replaced 1010 with 0110
        let x = _mm_setr_epi64x(z, 0);
        let expected = _mm_setr_epi64x(e, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = _mm_setr_epi64x(i, v);
        let r = _mm_insert_si64(x, y);
        assert_eq_m128i(r, expected);
    }

    #[repr(align(16))]
    struct MemoryF64 {
        data: [f64; 2],
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_stream_sd() {
        let mut mem = MemoryF64 {
            data: [1.0_f64, 2.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = _mm_setr_pd(3.0, 4.0);

            _mm_stream_sd(d, x);
        }
        assert_eq!(mem.data[0], 3.0);
        assert_eq!(mem.data[1], 2.0);
    }

    #[repr(align(16))]
    struct MemoryF32 {
        data: [f32; 4],
    }

    #[simd_test(enable = "sse4a")]
    unsafe fn test_mm_stream_ss() {
        let mut mem = MemoryF32 {
            data: [1.0_f32, 2.0, 3.0, 4.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = _mm_setr_ps(5.0, 6.0, 7.0, 8.0);

            _mm_stream_ss(d, x);
        }
        assert_eq!(mem.data[0], 5.0);
        assert_eq!(mem.data[1], 2.0);
        assert_eq!(mem.data[2], 3.0);
        assert_eq!(mem.data[3], 4.0);
    }
}
<|endoftext|>


<commit_before>// Higher level OpenCL wrappers.

use CL::*;
use CL::ll::*;

struct Platform {
    id: cl_platform_id
}

fn get_platforms() -> ~[Platform] {
    let mut num_platforms = 0;

    // TODO: Check result status
    clGetPlatformIDs(0, ptr::null(), ptr::addr_of(&num_platforms));

    let ids = vec::to_mut(vec::from_elem(num_platforms as uint,
                                         0 as cl_platform_id));

    do vec::as_imm_buf(ids) |ids, len| {
        clGetPlatformIDs(len as cl_uint,
                         ids, ptr::addr_of(&num_platforms))
    };

    do ids.map |id| { Platform { id: *id } }
}

struct Device {
    id: cl_device_id
}

fn get_devices(platform: Platform) -> ~[Device] {
    let mut num_devices = 0;

    clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, 0, ptr::null(),
                   ptr::addr_of(&num_devices));

    let ids = vec::to_mut(vec::from_elem(num_devices as uint,
                                         0 as cl_device_id));
    do vec::as_imm_buf(ids) |ids, len| {
        clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, len as cl_uint,
                       ids, ptr:addr_of(&num_devices));
    };

    error!("devices: %?", ids);

    do ids.map |id| { Device {id: *id }}
}

struct Context {
    ctx: cl_context,

    drop {
        clReleaseContext(self.ctx);
    }
}
<commit_msg>syntax error fixed.<commit_after>// Higher level OpenCL wrappers.

use CL::*;
use CL::ll::*;

struct Platform {
    id: cl_platform_id
}

fn get_platforms() -> ~[Platform] {
    let mut num_platforms = 0;

    // TODO: Check result status
    clGetPlatformIDs(0, ptr::null(), ptr::addr_of(&num_platforms));

    let ids = vec::to_mut(vec::from_elem(num_platforms as uint,
                                         0 as cl_platform_id));

    do vec::as_imm_buf(ids) |ids, len| {
        clGetPlatformIDs(len as cl_uint,
                         ids, ptr::addr_of(&num_platforms))
    };

    do ids.map |id| { Platform { id: *id } }
}

struct Device {
    id: cl_device_id
}

fn get_devices(platform: Platform) -> ~[Device] {
    let mut num_devices = 0;

    clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, 0, ptr::null(),
                   ptr::addr_of(&num_devices));

    let ids = vec::to_mut(vec::from_elem(num_devices as uint,
                                         0 as cl_device_id));
    do vec::as_imm_buf(ids) |ids, len| {
        clGetDeviceIDs(platform.id, CL_DEVICE_TYPE_GPU, len as cl_uint,
                       ids, ptr::addr_of(&num_devices));
    };

    error!("devices: %?", ids);

    do ids.map |id| { Device {id: *id }}
}

struct Context {
    ctx: cl_context,

    drop {
        clReleaseContext(self.ctx);
    }
}
<|endoftext|>


<commit_before>

#[cfg(windows)]
mod mmap {
    use libc::{CreateFileW, CreateFileMappingW, MapViewOfFile, CloseHandle, UnmapViewOfFile,
               GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, INVALID_HANDLE_VALUE, PAGE_READONLY,
               FILE_MAP_READ, HANDLE, TRUE};
    use libc::consts::os::extra::{FILE_FLAG_RANDOM_ACCESS};
    use libc::types::os::arch::extra::{LPCVOID};
    use std::ptr;
    struct Handle {
        hand: HANDLE,
    }
    impl Drop for Handle {
        fn drop(&mut self) {
            assert_eq!(unsafe { CloseHandle(self.hand) }, TRUE);
        }
    }
    struct MapView {
        data: LPCVOID,
    }
    impl Drop for MapView {
        fn drop(&mut self) {
            assert_eq!(unsafe { UnmapViewOfFile(self.data) }, TRUE);
        }
    }
    pub struct MapFile {
        view: MapView,
        map: Handle,
        file: Handle,
    }
    impl MapFile {
        pub fn data(&self) -> LPCVOID { self.view.data }
    }
    fn create_file(path: &Path) -> Result<Handle, &'static str> {
        let name = path.as_str().unwrap().to_utf16().append([0]);
        let file = unsafe {
            CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ, ptr::mut_null(),
                        OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, ptr::mut_null())
        };
        if file.to_uint() == INVALID_HANDLE_VALUE as uint { return Err("Failed to open file"); }
        Ok(Handle{hand: file})
    }
    fn create_mapping(file: &Handle) -> Result<Handle, &'static str> {
        let map = unsafe {
            CreateFileMappingW(file.hand, ptr::mut_null(), PAGE_READONLY, 0, 0, ptr::null())
        };
        if map.is_null() { return Err("Failed to create file mapping"); }
        Ok(Handle{hand: map})
    }
    fn map_view(map: &Handle) -> Result<MapView, &'static str> {
        let view = unsafe { MapViewOfFile(map.hand, FILE_MAP_READ, 0, 0, 0) };
        if view.is_null() { return Err("Failed to map view of file"); }
        Ok(MapView{data: view as *_})
    }
    pub fn open(path: &Path) -> Result<MapFile, &'static str> {
        let file = try!(create_file(path));
        let map = try!(create_mapping(&file));
        let view = try!(map_view(&map));
        Ok(MapFile{file: file, map: map, view: view})
    }
}
#[cfg(unix)]
mod mmap {
    use libc::{close, fstat, mmap, munmap, O_RDONLY, PROT_READ, stat, c_int, c_void};
    use libc::consts::os::posix88::{MAP_SHARED};
    use posix_open = libc::open;
    use std::mem::{uninitialized, transmute};
    use std::ptr;
    use std::io::fs::stat;
    struct Handle {
        hand: c_int,
    }
    impl Drop for Handle {
        fn drop(&mut self) {
            assert_eq!(unsafe { close(self.hand) }, 0);
        }
    }
    struct Mapping {
        data: *mut c_void,
        size: u64,
    }
    impl Drop for Mapping {
        fn drop(&mut self) {
            assert_eq!(unsafe { munmap(self.data as *c_void, self.size) }, 0);
        }
    }
    pub struct MapFile {
        map: Mapping,
        file: Handle,
    }
    impl MapFile {
        pub fn data(&self) -> * c_void { self.map.data as *_ }
    }
    fn open_file(path: &Path) -> Result<Handle, &'static str> {
        let name = path.to_c_str();
        let handle = posix_open(name.unwrap(), O_RDONLY, 0);
        if (handle == -1) { return Err("Failed to open file") }
        Ok(Handle{hand: handle})
    }
    fn file_size(path: &Path) -> Result<u64, &'static str> {
        match path.stat() {
            Ok(stat) => Ok(stat.size),
            Err(_) => Err("Failed to get file size")
        }
    }
    fn map_file(file: &Handle, size: u64) -> Result<Mapping, &'static str> {
        let map = mmap(ptr::null(), size as u64, PROT_READ, MAP_SHARED, file.hand, 0);
        if map.to_uint() == -1 { return Err("Failed to map file"); }
        Ok(Mapping{data: map, size: size})
    }
    pub fn open(path: &Path) -> Result<MapFile, &'static str> {
        let file = try!(open_file(path));
        let size = try!(file_size(path));
        let map = try!(map_file(&file, size));
        Ok(MapFile{file: file, map: map})
    }
}
pub struct File {
    map: mmap::MapFile,
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    pub fn open(path: &Path) -> Result<File, &'static str> {
        use std::mem::transmute;
        let map = try!(mmap::open(path));
        let data = map.data();
        let header: *Header = unsafe{ transmute(data) };
        if unsafe { (*header).magic } != 0x34474B50 {
            return Err("Not a valid NX PKG4 file");
        }
        unsafe {
            Ok(File{map: map, data: transmute(data), header: header,
                    nodetable: transmute(data.offset((*header).nodeoffset as int)),
                    stringtable: transmute(data.offset((*header).stringoffset as int))})
        }
    }
    fn header(&self) -> &Header {
        use std::mem::transmute;
        unsafe { transmute(self.header) }
    }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        use std::mem::transmute;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, |buf| {
                let bytes: &'a [u8] = transmute(buf);
                str::from_utf8(bytes)
            })
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> { self.file.get_str(self.data.name) }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                self.count -= 1;
                let node = Node{data: unsafe { &*self.data }, file: self.file,};
                self.data = unsafe { self.data.offset(1) };
                Some(node)
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<commit_msg>nx::mmap[unix]: Wrap unsafe calls in unsafe blocks<commit_after>

#[cfg(windows)]
mod mmap {
    use libc::{CreateFileW, CreateFileMappingW, MapViewOfFile, CloseHandle, UnmapViewOfFile,
               GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, INVALID_HANDLE_VALUE, PAGE_READONLY,
               FILE_MAP_READ, HANDLE, TRUE};
    use libc::consts::os::extra::{FILE_FLAG_RANDOM_ACCESS};
    use libc::types::os::arch::extra::{LPCVOID};
    use std::ptr;
    struct Handle {
        hand: HANDLE,
    }
    impl Drop for Handle {
        fn drop(&mut self) {
            assert_eq!(unsafe { CloseHandle(self.hand) }, TRUE);
        }
    }
    struct MapView {
        data: LPCVOID,
    }
    impl Drop for MapView {
        fn drop(&mut self) {
            assert_eq!(unsafe { UnmapViewOfFile(self.data) }, TRUE);
        }
    }
    pub struct MapFile {
        view: MapView,
        map: Handle,
        file: Handle,
    }
    impl MapFile {
        pub fn data(&self) -> LPCVOID { self.view.data }
    }
    fn create_file(path: &Path) -> Result<Handle, &'static str> {
        let name = path.as_str().unwrap().to_utf16().append([0]);
        let file = unsafe {
            CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ, ptr::mut_null(),
                        OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, ptr::mut_null())
        };
        if file.to_uint() == INVALID_HANDLE_VALUE as uint { return Err("Failed to open file"); }
        Ok(Handle{hand: file})
    }
    fn create_mapping(file: &Handle) -> Result<Handle, &'static str> {
        let map = unsafe {
            CreateFileMappingW(file.hand, ptr::mut_null(), PAGE_READONLY, 0, 0, ptr::null())
        };
        if map.is_null() { return Err("Failed to create file mapping"); }
        Ok(Handle{hand: map})
    }
    fn map_view(map: &Handle) -> Result<MapView, &'static str> {
        let view = unsafe { MapViewOfFile(map.hand, FILE_MAP_READ, 0, 0, 0) };
        if view.is_null() { return Err("Failed to map view of file"); }
        Ok(MapView{data: view as *_})
    }
    pub fn open(path: &Path) -> Result<MapFile, &'static str> {
        let file = try!(create_file(path));
        let map = try!(create_mapping(&file));
        let view = try!(map_view(&map));
        Ok(MapFile{file: file, map: map, view: view})
    }
}
#[cfg(unix)]
mod mmap {
    use libc::{close, fstat, mmap, munmap, O_RDONLY, PROT_READ, stat, c_int, c_void};
    use libc::consts::os::posix88::{MAP_SHARED};
    use posix_open = libc::open;
    use std::mem::{uninitialized, transmute};
    use std::ptr;
    use std::io::fs::stat;
    struct Handle {
        hand: c_int,
    }
    impl Drop for Handle {
        fn drop(&mut self) {
            assert_eq!(unsafe { close(self.hand) }, 0);
        }
    }
    struct Mapping {
        data: *mut c_void,
        size: u64,
    }
    impl Drop for Mapping {
        fn drop(&mut self) {
            assert_eq!(unsafe { munmap(self.data as *c_void, self.size) }, 0);
        }
    }
    pub struct MapFile {
        map: Mapping,
        file: Handle,
    }
    impl MapFile {
        pub fn data(&self) -> * c_void { self.map.data as *_ }
    }
    fn open_file(path: &Path) -> Result<Handle, &'static str> {
        let name = path.to_c_str();
        let handle = unsafe {
             posix_open(name.unwrap(), O_RDONLY, 0)
        };
        if (handle == -1) { return Err("Failed to open file") }
        Ok(Handle{hand: handle})
    }
    fn file_size(path: &Path) -> Result<u64, &'static str> {
        match path.stat() {
            Ok(stat) => Ok(stat.size),
            Err(_) => Err("Failed to get file size")
        }
    }
    fn map_file(file: &Handle, size: u64) -> Result<Mapping, &'static str> {
        let map = unsafe {
            mmap(ptr::null(), size as u64, PROT_READ, MAP_SHARED, file.hand, 0)
        };
        if map.to_uint() == -1 { return Err("Failed to map file"); }
        Ok(Mapping{data: map, size: size})
    }
    pub fn open(path: &Path) -> Result<MapFile, &'static str> {
        let file = try!(open_file(path));
        let size = try!(file_size(path));
        let map = try!(map_file(&file, size));
        Ok(MapFile{file: file, map: map})
    }
}
pub struct File {
    map: mmap::MapFile,
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    pub fn open(path: &Path) -> Result<File, &'static str> {
        use std::mem::transmute;
        let map = try!(mmap::open(path));
        let data = map.data();
        let header: *Header = unsafe{ transmute(data) };
        if unsafe { (*header).magic } != 0x34474B50 {
            return Err("Not a valid NX PKG4 file");
        }
        unsafe {
            Ok(File{map: map, data: transmute(data), header: header,
                    nodetable: transmute(data.offset((*header).nodeoffset as int)),
                    stringtable: transmute(data.offset((*header).stringoffset as int))})
        }
    }
    fn header(&self) -> &Header {
        use std::mem::transmute;
        unsafe { transmute(self.header) }
    }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        use std::mem::transmute;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, |buf| {
                let bytes: &'a [u8] = transmute(buf);
                str::from_utf8(bytes)
            })
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> { self.file.get_str(self.data.name) }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                self.count -= 1;
                let node = Node{data: unsafe { &*self.data }, file: self.file,};
                self.data = unsafe { self.data.offset(1) };
                Some(node)
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<|endoftext|>


<commit_before>/*!

BWT (Burrows-Wheeler Transform) forward and backward transformation

This module contains a bruteforce implementation of BWT encoding in Rust as well as standard decoding.
These are exposed as a standard `Reader` and `Writer` interfaces wrapping an underlying stream.

# Example

```rust
let stream = Path::new("path/to/file.bwt");
let decompressed = bwt::Decoder::new(stream,true).read_to_end();
```

# Credit

*/

use std::{iter,num,vec};

static MAGIC    : u32   = 0x74776272;	//=rbwt

struct Radix    {
    freq    : [uint,..257],
}

impl Radix  {
    /// create Radix sort instance
    fn new() -> Radix   {
        Radix   {
            freq : [0,..257],
        }
    }

    /// reset counters
    /// allows the struct to be re-used
    #[allow(dead_code)]
    fn reset(&mut self) {
        for i in range(0,257)   {
            self.freq[i] = 0;
        }
    }

    /// count elements in the input
    fn gather(&mut self, input: &[u8])  {
        for &b in input.iter()  {
            self.freq[b] += 1;
        }
    }

    /// build offset table
    fn accumulate(&mut self)    {
        let mut n = 0;
        for i in range(0,256)   {
            let f = self.freq[i];
            self.freq[i] = n;
            n += f;
        }
        self.freq[256] = n;
    }

    /// return next byte position
    fn position(&mut self, b: u8)-> uint   {
        let pos = self.freq[b];
        self.freq[b] += 1;
        assert!( self.freq[b] <= self.freq[b+1] );
        pos
    }

    /// shift frequences to the left
    /// allows the offsets to be re-used after all positions are obtained
    #[allow(dead_code)]
    fn shift(&mut self) {
        assert_eq!( self.freq[255], self.freq[256] );
        for i in range(256,0)   {
            self.freq[i] = self.freq[i-1];
        }
        self.freq[0] = 0;
    }
}

/// This structure is used to decode a stream of BWT blocks. This wraps an
/// internal reader which is read from when this decoder's read method is
/// called.
pub struct Decoder<R> {
    /// The internally wrapped reader. This is exposed so it may be moved out
    /// of. Note that if data is read from the reader while decoding is in
    /// progress the output stream will get corrupted.
    r: R,
    priv start  : uint,

    priv temp   : ~[u8],
    priv output : ~[u8],
    priv table  : ~[uint],

    priv header         : bool,
    priv max_block_size : uint,
    priv extra_memory   : bool,
}

impl<R: Reader> Decoder<R> {
    /// Creates a new decoder which will read data from the given stream. The
    /// inner stream can be re-acquired by moving out of the `r` field of this
    /// structure.
    /// 'extra' switch allows allocating extra N words of memory for better performance
    pub fn new(r: R, extra: bool) -> Decoder<R> {
        Decoder {
            r: r,
            start: 0,
            temp: ~[],
            output: ~[],
            table: ~[],
            header: false,
            max_block_size: 0,
            extra_memory: extra,
        }
    }

    /// Resets this decoder back to its initial state. Note that the underlying
    /// stream is not seeked on or has any alterations performed on it.
    pub fn reset(&mut self) {
        self.header = false;
        self.start = 0;
    }

    fn read_header(&mut self) -> Option<()> {
        if self.r.read_le_u32() != MAGIC { return None }
        self.max_block_size = self.r.read_le_u32() as uint;

        debug!("max size: {}", self.max_block_size);

        return Some(());
    }

    fn decode_block(&mut self) -> bool {
        let n = self.r.read_le_u32() as uint;
        if n==0 { return false }

        //TODO: insert a dummy $ to avoid an extra if later on
        self.temp.truncate(0);
        self.temp.reserve(n);
        self.r.push_bytes(&mut self.temp, n);

        let mut radix = Radix::new();
        radix.gather( self.temp );
        radix.accumulate();

        let origin = self.r.read_le_u32() as uint + 1;
        self.output.truncate(0);
        self.output.reserve(n);

        if self.extra_memory    {
            self.table.truncate(0);
            self.table.grow_fn(n+1, |_| 0);
            for i in range(0,n) {
                let b = self.temp[i];
                let p = radix.position(b);
                self.table[p+1] = if i<origin {i} else {i+1};
            }
            let mut i = origin;
            n.times(|| {
                i = self.table[i];
                let j = if i>origin {i-1} else {i};
                self.output.push( self.temp[j] );
            });
            assert_eq!(i, 0);
        }else   {
            self.output.grow_fn(n, |_| 0);
            let mut i = 0;
            for j in range(0,n) {
                let b = self.temp[if i>origin {i-1} else {i}];
                self.output[n-1-j] = b;
                i = (if i>origin {0} else {1}) + radix.freq[b] +
                    self.temp.slice_to(i).iter().count(|&k| k==b);
            }
            assert_eq!(i, origin);
        }

        self.start = 0;
        return true;
    }
}

impl<R: Reader> Reader for Decoder<R> {
    fn read(&mut self, dst: &mut [u8]) -> Option<uint> {
        if !self.header {
            self.read_header();
            self.header = true;
        }
        let mut amt = dst.len();
        let len = amt;

        while amt > 0 {
            if self.output.len() == self.start {
                if !self.decode_block() {
                   break
                }
            }
            let n = num::min( amt, self.output.len() - self.start );
            vec::bytes::copy_memory(
                dst.mut_slice_from(len - amt),
                self.output.slice_from(self.start)
                );
            self.start += n;
            amt -= n;
        }

        if len == amt {None} else {Some(len - amt)}
    }
}

/// This structure is used to compress a stream of bytes using the BWT.
/// This is a wrapper around an internal writer which bytes will be written to.
pub struct Encoder<W> {
    priv w: W,
    priv buf: ~[u8],
    priv suf: ~[uint],
    priv wrote_header: bool,
    priv block_size: uint,
}

impl<W: Writer> Encoder<W> {
    /// Creates a new encoder which will have its output written to the given
    /// output stream. The output stream can be re-acquired by calling
    /// `finish()`
    /// 'block_size' is idealy as big as your input, unless you know for sure that
    /// the input consists of multiple parts of different nature. Often set as 4Mb.
    pub fn new(w: W, block_size: uint) -> Encoder<W> {
        Encoder {
            w: w,
            buf: ~[],
            suf: ~[],
            wrote_header: false,
            block_size: block_size,
        }
    }

    fn encode_block(&mut self) {
        let n = self.buf.len();
        self.w.write_le_u32(n as u32);

        let mut radix = Radix::new();
        radix.gather( self.buf );
        radix.accumulate();

        self.suf.truncate(0);
        self.suf.grow_fn(n, |_| n);
        for i in range(0,n) {
            let b = self.buf[i];
            let p = radix.position(b);
            self.suf[p] = i;
        }

        for i in range(0,256)   {
            let lo = radix.freq[i];
            let hi = radix.freq[i+1];
            let slice = self.suf.mut_slice(lo,hi);
            slice.sort_by(|&a,&b| {
                iter::order::cmp(
                    self.buf.slice_from(a).iter(),
                    self.buf.slice_from(b).iter())
            });
        }

        let mut origin = n;
        self.w.write_u8( self.buf[n-1] );

        for i in range(0,n) {
            let s = self.suf[i];
            if s==0 {
                assert!( origin == n );
                origin = i;
            }else   {
                let b = self.buf[s-1];
                self.w.write_u8( b );
            }
        }
        assert!( origin != n );
        self.w.write_le_u32(origin as u32);
        self.buf.truncate(0);
    }

    /// This function is used to flag that this session of compression is done
    /// with. The stream is finished up (final bytes are written), and then the
    /// wrapped writer is returned.
    pub fn finish(mut self) -> W {
        self.flush();
        self.w
    }
}

impl<W: Writer> Writer for Encoder<W> {
    fn write(&mut self, mut buf: &[u8]) {
        if !self.wrote_header {
            self.w.write_le_u32(MAGIC);
            self.w.write_le_u32(self.block_size as u32);
            self.wrote_header = true;
        }

        while buf.len() > 0 {
            let amt = num::min( self.block_size - self.buf.len(), buf.len() );
            self.buf.push_all( buf.slice_to(amt) );

            if self.buf.len() == self.block_size {
                self.encode_block();
            }
            buf = buf.slice_from(amt);
        }
    }

    fn flush(&mut self) {
        if self.buf.len() > 0 {
            self.encode_block();
        }
    }
}

#[cfg(test)]
mod test {
    use extra::test;
    //use std::rand;
    use std::io::{BufReader, MemWriter};
    use super::{Decoder, Encoder};

    fn test_decode(input: &[u8], output: &[u8], extra_memory: bool) {
        let mut d = Decoder::new( BufReader::new(input), extra_memory );

        let got = d.read_to_end();
        assert!( got.as_slice() == output );
    }

    #[test]
    fn decode() {
        let reference = include_bin!("data/test.txt");
        test_decode(include_bin!("data/test.bwt"), reference, true);
        test_decode(include_bin!("data/test.bwt"), reference, false);
    }

    fn roundtrip(bytes: &[u8]) {
        let mut e = Encoder::new( MemWriter::new(), 1<<10 );
        e.write(bytes);
        let encoded = e.finish().unwrap();

        let mut d = Decoder::new( BufReader::new(encoded), true );
        let decoded = d.read_to_end();
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips() {
        roundtrip(bytes!("test"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("data/test.txt"));
    }

    #[bench]
    fn decompress_speed(bh: &mut test::BenchHarness) {
        let input = include_bin!("data/test.bwt");
        let mut d = Decoder::new( BufReader::new(input), true );
        let mut output = [0u8, ..65536];
        let mut output_size = 0;
        bh.iter(|| {
            d.r = BufReader::new(input);
            d.reset();
            output_size = d.read(output).unwrap();
        });
        bh.bytes = output_size as u64;
    }
}
<commit_msg>Update with removal of times<commit_after>/*!

BWT (Burrows-Wheeler Transform) forward and backward transformation

This module contains a bruteforce implementation of BWT encoding in Rust as well as standard decoding.
These are exposed as a standard `Reader` and `Writer` interfaces wrapping an underlying stream.

# Example

```rust
let stream = Path::new("path/to/file.bwt");
let decompressed = bwt::Decoder::new(stream,true).read_to_end();
```

# Credit

*/

use std::{iter,num,vec};

static MAGIC    : u32   = 0x74776272;	//=rbwt

struct Radix    {
    freq    : [uint,..257],
}

impl Radix  {
    /// create Radix sort instance
    fn new() -> Radix   {
        Radix   {
            freq : [0,..257],
        }
    }

    /// reset counters
    /// allows the struct to be re-used
    #[allow(dead_code)]
    fn reset(&mut self) {
        for i in range(0,257)   {
            self.freq[i] = 0;
        }
    }

    /// count elements in the input
    fn gather(&mut self, input: &[u8])  {
        for &b in input.iter()  {
            self.freq[b] += 1;
        }
    }

    /// build offset table
    fn accumulate(&mut self)    {
        let mut n = 0;
        for i in range(0,256)   {
            let f = self.freq[i];
            self.freq[i] = n;
            n += f;
        }
        self.freq[256] = n;
    }

    /// return next byte position
    fn position(&mut self, b: u8)-> uint   {
        let pos = self.freq[b];
        self.freq[b] += 1;
        assert!( self.freq[b] <= self.freq[b+1] );
        pos
    }

    /// shift frequences to the left
    /// allows the offsets to be re-used after all positions are obtained
    #[allow(dead_code)]
    fn shift(&mut self) {
        assert_eq!( self.freq[255], self.freq[256] );
        for i in range(256,0)   {
            self.freq[i] = self.freq[i-1];
        }
        self.freq[0] = 0;
    }
}

/// This structure is used to decode a stream of BWT blocks. This wraps an
/// internal reader which is read from when this decoder's read method is
/// called.
pub struct Decoder<R> {
    /// The internally wrapped reader. This is exposed so it may be moved out
    /// of. Note that if data is read from the reader while decoding is in
    /// progress the output stream will get corrupted.
    r: R,
    priv start  : uint,

    priv temp   : ~[u8],
    priv output : ~[u8],
    priv table  : ~[uint],

    priv header         : bool,
    priv max_block_size : uint,
    priv extra_memory   : bool,
}

impl<R: Reader> Decoder<R> {
    /// Creates a new decoder which will read data from the given stream. The
    /// inner stream can be re-acquired by moving out of the `r` field of this
    /// structure.
    /// 'extra' switch allows allocating extra N words of memory for better performance
    pub fn new(r: R, extra: bool) -> Decoder<R> {
        Decoder {
            r: r,
            start: 0,
            temp: ~[],
            output: ~[],
            table: ~[],
            header: false,
            max_block_size: 0,
            extra_memory: extra,
        }
    }

    /// Resets this decoder back to its initial state. Note that the underlying
    /// stream is not seeked on or has any alterations performed on it.
    pub fn reset(&mut self) {
        self.header = false;
        self.start = 0;
    }

    fn read_header(&mut self) -> Option<()> {
        if self.r.read_le_u32() != MAGIC { return None }
        self.max_block_size = self.r.read_le_u32() as uint;

        debug!("max size: {}", self.max_block_size);

        return Some(());
    }

    fn decode_block(&mut self) -> bool {
        let n = self.r.read_le_u32() as uint;
        if n==0 { return false }

        //TODO: insert a dummy $ to avoid an extra if later on
        self.temp.truncate(0);
        self.temp.reserve(n);
        self.r.push_bytes(&mut self.temp, n);

        let mut radix = Radix::new();
        radix.gather( self.temp );
        radix.accumulate();

        let origin = self.r.read_le_u32() as uint + 1;
        self.output.truncate(0);
        self.output.reserve(n);

        if self.extra_memory    {
            self.table.truncate(0);
            self.table.grow_fn(n+1, |_| 0);
            for i in range(0,n) {
                let b = self.temp[i];
                let p = radix.position(b);
                self.table[p+1] = if i<origin {i} else {i+1};
            }
            let mut i = origin;
            for _ in range(0, n) {
                i = self.table[i];
                let j = if i>origin {i-1} else {i};
                self.output.push( self.temp[j] );
            }
            assert_eq!(i, 0);
        }else   {
            self.output.grow_fn(n, |_| 0);
            let mut i = 0;
            for j in range(0,n) {
                let b = self.temp[if i>origin {i-1} else {i}];
                self.output[n-1-j] = b;
                i = (if i>origin {0} else {1}) + radix.freq[b] +
                    self.temp.slice_to(i).iter().count(|&k| k==b);
            }
            assert_eq!(i, origin);
        }

        self.start = 0;
        return true;
    }
}

impl<R: Reader> Reader for Decoder<R> {
    fn read(&mut self, dst: &mut [u8]) -> Option<uint> {
        if !self.header {
            self.read_header();
            self.header = true;
        }
        let mut amt = dst.len();
        let len = amt;

        while amt > 0 {
            if self.output.len() == self.start {
                if !self.decode_block() {
                   break
                }
            }
            let n = num::min( amt, self.output.len() - self.start );
            vec::bytes::copy_memory(
                dst.mut_slice_from(len - amt),
                self.output.slice_from(self.start)
                );
            self.start += n;
            amt -= n;
        }

        if len == amt {None} else {Some(len - amt)}
    }
}

/// This structure is used to compress a stream of bytes using the BWT.
/// This is a wrapper around an internal writer which bytes will be written to.
pub struct Encoder<W> {
    priv w: W,
    priv buf: ~[u8],
    priv suf: ~[uint],
    priv wrote_header: bool,
    priv block_size: uint,
}

impl<W: Writer> Encoder<W> {
    /// Creates a new encoder which will have its output written to the given
    /// output stream. The output stream can be re-acquired by calling
    /// `finish()`
    /// 'block_size' is idealy as big as your input, unless you know for sure that
    /// the input consists of multiple parts of different nature. Often set as 4Mb.
    pub fn new(w: W, block_size: uint) -> Encoder<W> {
        Encoder {
            w: w,
            buf: ~[],
            suf: ~[],
            wrote_header: false,
            block_size: block_size,
        }
    }

    fn encode_block(&mut self) {
        let n = self.buf.len();
        self.w.write_le_u32(n as u32);

        let mut radix = Radix::new();
        radix.gather( self.buf );
        radix.accumulate();

        self.suf.truncate(0);
        self.suf.grow_fn(n, |_| n);
        for i in range(0,n) {
            let b = self.buf[i];
            let p = radix.position(b);
            self.suf[p] = i;
        }

        for i in range(0,256)   {
            let lo = radix.freq[i];
            let hi = radix.freq[i+1];
            let slice = self.suf.mut_slice(lo,hi);
            slice.sort_by(|&a,&b| {
                iter::order::cmp(
                    self.buf.slice_from(a).iter(),
                    self.buf.slice_from(b).iter())
            });
        }

        let mut origin = n;
        self.w.write_u8( self.buf[n-1] );

        for i in range(0,n) {
            let s = self.suf[i];
            if s==0 {
                assert!( origin == n );
                origin = i;
            }else   {
                let b = self.buf[s-1];
                self.w.write_u8( b );
            }
        }
        assert!( origin != n );
        self.w.write_le_u32(origin as u32);
        self.buf.truncate(0);
    }

    /// This function is used to flag that this session of compression is done
    /// with. The stream is finished up (final bytes are written), and then the
    /// wrapped writer is returned.
    pub fn finish(mut self) -> W {
        self.flush();
        self.w
    }
}

impl<W: Writer> Writer for Encoder<W> {
    fn write(&mut self, mut buf: &[u8]) {
        if !self.wrote_header {
            self.w.write_le_u32(MAGIC);
            self.w.write_le_u32(self.block_size as u32);
            self.wrote_header = true;
        }

        while buf.len() > 0 {
            let amt = num::min( self.block_size - self.buf.len(), buf.len() );
            self.buf.push_all( buf.slice_to(amt) );

            if self.buf.len() == self.block_size {
                self.encode_block();
            }
            buf = buf.slice_from(amt);
        }
    }

    fn flush(&mut self) {
        if self.buf.len() > 0 {
            self.encode_block();
        }
    }
}

#[cfg(test)]
mod test {
    use extra::test;
    //use std::rand;
    use std::io::{BufReader, MemWriter};
    use super::{Decoder, Encoder};

    fn test_decode(input: &[u8], output: &[u8], extra_memory: bool) {
        let mut d = Decoder::new( BufReader::new(input), extra_memory );

        let got = d.read_to_end();
        assert!( got.as_slice() == output );
    }

    #[test]
    fn decode() {
        let reference = include_bin!("data/test.txt");
        test_decode(include_bin!("data/test.bwt"), reference, true);
        test_decode(include_bin!("data/test.bwt"), reference, false);
    }

    fn roundtrip(bytes: &[u8]) {
        let mut e = Encoder::new( MemWriter::new(), 1<<10 );
        e.write(bytes);
        let encoded = e.finish().unwrap();

        let mut d = Decoder::new( BufReader::new(encoded), true );
        let decoded = d.read_to_end();
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips() {
        roundtrip(bytes!("test"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("data/test.txt"));
    }

    #[bench]
    fn decompress_speed(bh: &mut test::BenchHarness) {
        let input = include_bin!("data/test.bwt");
        let mut d = Decoder::new( BufReader::new(input), true );
        let mut output = [0u8, ..65536];
        let mut output_size = 0;
        bh.iter(|| {
            d.r = BufReader::new(input);
            d.reset();
            output_size = d.read(output).unwrap();
        });
        bh.bytes = output_size as u64;
    }
}
<|endoftext|>