<commit_before>use std::cell::RefCell;
use std::fmt;
use std::num::NonZeroU64;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};

use crate::stacked_borrows::{AccessKind, SbTag};
use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(String),
    UnsupportedInIsolation(String),
    ExperimentalUb {
        msg: String,
        url: String,
    },
    Deadlock,
    MultipleSymbolDefinitions {
        link_name: Symbol,
        first: SpanData,
        first_crate: Symbol,
        second: SpanData,
        second_crate: Symbol,
    },
    SymbolShimClashing {
        link_name: Symbol,
        span: SpanData,
    },
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) => write!(f, "the evaluated program completed with exit code {}", code),
            Abort(msg) => write!(f, "{}", msg),
            UnsupportedInIsolation(msg) => write!(f, "{}", msg),
            ExperimentalUb { msg, .. } => write!(f, "{}", msg),
            Deadlock => write!(f, "the evaluated program deadlocked"),
            MultipleSymbolDefinitions { link_name, .. } =>
                write!(f, "multiple definitions of symbol `{}`", link_name),
            SymbolShimClashing { link_name, .. } =>
                write!(
                    f,
                    "found `{}` symbol definition that clashes with a built-in shim",
                    link_name
                ),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    CreatedPointerTag(NonZeroU64),
    /// This `Item` was popped from the borrow stack, either due to a grant of
    /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`.
    PoppedPointerTag(Item, Option<(SbTag, AccessKind)>),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
    RejectedIsolatedOp(String),
}

/// Level of Miri specific diagnostics
enum DiagLevel {
    Error,
    Warning,
    Note,
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind() {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) => Some("abnormal termination"),
                UnsupportedInIsolation(_) => Some("unsupported operation"),
                ExperimentalUb { .. } => Some("Undefined Behavior"),
                Deadlock => Some("deadlock"),
                MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
            };
            #[rustfmt::skip]
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![
                        (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
                        (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
                    ],
                ExperimentalUb { url, .. } =>
                    vec![
                        (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
                        (None, format!("see {} for further information", url)),
                    ],
                MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                    vec![
                        (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
                        (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
                    ],
                SymbolShimClashing { link_name, span } =>
                    vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            #[rustfmt::skip]
            let title = match e.kind() {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                InvalidProgram(InvalidProgramInfo::ReferencedConstant) =>
                    "post-monomorphization error",
                InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) =>
                    "error occurred",
                kind =>
                    bug!("This error should be impossible in Miri: {:?}", kind),
            };
            #[rustfmt::skip]
            let helps = match e.kind() {
                Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind()),
                Unsupported(_) =>
                    vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
                    if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
                =>
                    vec![
                        (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
                        (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                        (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                    ],
                _ => vec![],
            };
            (Some(title), helps)
        }
    };

    let mut stacktrace = ecx.generate_stacktrace();
    let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local());
    match ecx.machine.backtrace_style {
        BacktraceStyle::Off => {
            // Retain one frame so that we can print a span for the error itself
            stacktrace.truncate(1);
        }
        BacktraceStyle::Short => {
            // Only prune frames if there is at least one local frame. This check ensures that if
            // we get a backtrace that never makes it to the user code because it has detected a
            // bug in the Rust runtime, we don't prune away every frame.
            if has_local_frame {
                // This is part of the logic that `std` uses to select the relevant part of a
                // backtrace. But here, we only look for __rust_begin_short_backtrace, not
                // __rust_end_short_backtrace because the end symbol comes from a call to the default
                // panic handler.
                stacktrace = stacktrace
                    .into_iter()
                    .take_while(|frame| {
                        let def_id = frame.instance.def_id();
                        let path = ecx.tcx.tcx.def_path_str(def_id);
                        !path.contains("__rust_begin_short_backtrace")
                    })
                    .collect::<Vec<_>>();

                // After we prune frames from the bottom, there are a few left that are part of the
                // Rust runtime. So we remove frames until we get to a local symbol, which should be
                // main or a test.
                // This len check ensures that we don't somehow remove every frame, as doing so breaks
                // the primary error message.
                while stacktrace.len() > 1
                    && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
                {
                    stacktrace.pop();
                }
            }
        }
        BacktraceStyle::Full => {}
    }

    e.print_backtrace();
    let msg = e.to_string();
    report_msg(
        *ecx.tcx,
        DiagLevel::Error,
        &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
        msg,
        helps,
        &stacktrace,
    );

    // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
    // do not include a note when backtraces are off.
    if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame {
        ecx.tcx.sess.diagnostic().note_without_error(
            "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
        );
    }

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind() {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_offset.bytes(),
                access.uninit_offset.bytes() + access.uninit_size.bytes(),
            );
            eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id));
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    diag_level: DiagLevel,
    title: &str,
    span_msg: String,
    mut helps: Vec<(Option<SpanData>, String)>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = match diag_level {
        DiagLevel::Error => tcx.sess.struct_span_err(span, title),
        DiagLevel::Warning => tcx.sess.struct_span_warn(span, title),
        DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title),
    };

    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().1.push_str("\n");
        for (span_data, help) in helps {
            if let Some(span_data) = span_data {
                err.span_help(span_data.span(), &help);
            } else {
                err.help(&help);
            }
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_span(),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(
                    stacktrace.len() == info.stack_size - 1,
                    "we should never pop more than one frame at once"
                );
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(
                    stacktrace[0].instance, instance,
                    "we should not pop and push a frame in one step"
                );
            }

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    CreatedPointerTag(tag) => format!("created tag {:?}", tag),
                    PoppedPointerTag(item, tag) =>
                        match tag {
                            None =>
                                format!(
                                    "popped tracked tag for item {:?} due to deallocation",
                                    item
                                ),
                            Some((tag, access)) => {
                                format!(
                                    "popped tracked tag for item {:?} due to {:?} access for {:?}",
                                    item, access, tag
                                )
                            }
                        },
                    CreatedCallId(id) => format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id),
                    RejectedIsolatedOp(ref op) =>
                        format!("{} was made to return an error due to isolation", op),
                };

                let (title, diag_level) = match e {
                    RejectedIsolatedOp(_) =>
                        ("operation rejected by isolation", DiagLevel::Warning),
                    _ => ("tracking was triggered", DiagLevel::Note),
                };

                report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace);
            }
        });
    }
}
<commit_msg>Prune stacktraces for tag-tracking diagnostics too<commit_after>use std::cell::RefCell;
use std::fmt;
use std::num::NonZeroU64;

use log::trace;

use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};

use crate::stacked_borrows::{AccessKind, SbTag};
use crate::*;

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    Abort(String),
    UnsupportedInIsolation(String),
    ExperimentalUb {
        msg: String,
        url: String,
    },
    Deadlock,
    MultipleSymbolDefinitions {
        link_name: Symbol,
        first: SpanData,
        first_crate: Symbol,
        second: SpanData,
        second_crate: Symbol,
    },
    SymbolShimClashing {
        link_name: Symbol,
        span: SpanData,
    },
}

impl fmt::Display for TerminationInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TerminationInfo::*;
        match self {
            Exit(code) => write!(f, "the evaluated program completed with exit code {}", code),
            Abort(msg) => write!(f, "{}", msg),
            UnsupportedInIsolation(msg) => write!(f, "{}", msg),
            ExperimentalUb { msg, .. } => write!(f, "{}", msg),
            Deadlock => write!(f, "the evaluated program deadlocked"),
            MultipleSymbolDefinitions { link_name, .. } =>
                write!(f, "multiple definitions of symbol `{}`", link_name),
            SymbolShimClashing { link_name, .. } =>
                write!(
                    f,
                    "found `{}` symbol definition that clashes with a built-in shim",
                    link_name
                ),
        }
    }
}

impl MachineStopType for TerminationInfo {}

/// Miri specific diagnostics
pub enum NonHaltingDiagnostic {
    CreatedPointerTag(NonZeroU64),
    /// This `Item` was popped from the borrow stack, either due to a grant of
    /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`.
    PoppedPointerTag(Item, Option<(SbTag, AccessKind)>),
    CreatedCallId(CallId),
    CreatedAlloc(AllocId),
    FreedAlloc(AllocId),
    RejectedIsolatedOp(String),
}

/// Level of Miri specific diagnostics
enum DiagLevel {
    Error,
    Warning,
    Note,
}

fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool {
    stacktrace.iter().any(|frame| frame.instance.def_id().is_local())
}

fn prune_stacktrace<'mir, 'tcx>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    mut stacktrace: Vec<FrameInfo<'tcx>>,
) -> Vec<FrameInfo<'tcx>> {
    match ecx.machine.backtrace_style {
        BacktraceStyle::Off => {
            // Retain one frame so that we can print a span for the error itself
            stacktrace.truncate(1);
        }
        BacktraceStyle::Short => {
            // Only prune frames if there is at least one local frame. This check ensures that if
            // we get a backtrace that never makes it to the user code because it has detected a
            // bug in the Rust runtime, we don't prune away every frame.
            if has_local_frame(&stacktrace) {
                // This is part of the logic that `std` uses to select the relevant part of a
                // backtrace. But here, we only look for __rust_begin_short_backtrace, not
                // __rust_end_short_backtrace because the end symbol comes from a call to the default
                // panic handler.
                stacktrace = stacktrace
                    .into_iter()
                    .take_while(|frame| {
                        let def_id = frame.instance.def_id();
                        let path = ecx.tcx.tcx.def_path_str(def_id);
                        !path.contains("__rust_begin_short_backtrace")
                    })
                    .collect::<Vec<_>>();

                // After we prune frames from the bottom, there are a few left that are part of the
                // Rust runtime. So we remove frames until we get to a local symbol, which should be
                // main or a test.
                // This len check ensures that we don't somehow remove every frame, as doing so breaks
                // the primary error message.
                while stacktrace.len() > 1
                    && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
                {
                    stacktrace.pop();
                }
            }
        }
        BacktraceStyle::Full => {}
    }
    stacktrace
}

/// Emit a custom diagnostic without going through the miri-engine machinery
pub fn report_error<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
    e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    use InterpError::*;

    let (title, helps) = match &e.kind() {
        MachineStop(info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            use TerminationInfo::*;
            let title = match info {
                Exit(code) => return Some(*code),
                Abort(_) => Some("abnormal termination"),
                UnsupportedInIsolation(_) => Some("unsupported operation"),
                ExperimentalUb { .. } => Some("Undefined Behavior"),
                Deadlock => Some("deadlock"),
                MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
            };
            #[rustfmt::skip]
            let helps = match info {
                UnsupportedInIsolation(_) =>
                    vec![
                        (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
                        (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
                    ],
                ExperimentalUb { url, .. } =>
                    vec![
                        (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
                        (None, format!("see {} for further information", url)),
                    ],
                MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                    vec![
                        (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
                        (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
                    ],
                SymbolShimClashing { link_name, span } =>
                    vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))],
                _ => vec![],
            };
            (title, helps)
        }
        _ => {
            #[rustfmt::skip]
            let title = match e.kind() {
                Unsupported(_) =>
                    "unsupported operation",
                UndefinedBehavior(_) =>
                    "Undefined Behavior",
                ResourceExhaustion(_) =>
                    "resource exhaustion",
                InvalidProgram(InvalidProgramInfo::ReferencedConstant) =>
                    "post-monomorphization error",
                InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) =>
                    "error occurred",
                kind =>
                    bug!("This error should be impossible in Miri: {:?}", kind),
            };
            #[rustfmt::skip]
            let helps = match e.kind() {
                Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
                    panic!("Error should never be raised by Miri: {:?}", e.kind()),
                Unsupported(_) =>
                    vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
                UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
                    if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
                =>
                    vec![
                        (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
                        (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
                    ],
                UndefinedBehavior(_) =>
                    vec![
                        (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
                        (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
                    ],
                _ => vec![],
            };
            (Some(title), helps)
        }
    };

    let stacktrace = ecx.generate_stacktrace();
    let stacktrace = prune_stacktrace(ecx, stacktrace);
    e.print_backtrace();
    let msg = e.to_string();
    report_msg(
        *ecx.tcx,
        DiagLevel::Error,
        &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
        msg,
        helps,
        &stacktrace,
    );

    // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
    // do not include a note when backtraces are off.
    if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) {
        ecx.tcx.sess.diagnostic().note_without_error(
            "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
        );
    }

    // Debug-dump all locals.
    for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }

    // Extra output to help debug specific issues.
    match e.kind() {
        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
            eprintln!(
                "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:",
                access.uninit_offset.bytes(),
                access.uninit_offset.bytes() + access.uninit_size.bytes(),
            );
            eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id));
        }
        _ => {}
    }

    None
}

/// Report an error or note (depending on the `error` argument) with the given stacktrace.
/// Also emits a full stacktrace of the interpreter stack.
fn report_msg<'tcx>(
    tcx: TyCtxt<'tcx>,
    diag_level: DiagLevel,
    title: &str,
    span_msg: String,
    mut helps: Vec<(Option<SpanData>, String)>,
    stacktrace: &[FrameInfo<'tcx>],
) {
    let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
    let mut err = match diag_level {
        DiagLevel::Error => tcx.sess.struct_span_err(span, title),
        DiagLevel::Warning => tcx.sess.struct_span_warn(span, title),
        DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title),
    };

    // Show main message.
    if span != DUMMY_SP {
        err.span_label(span, span_msg);
    } else {
        // Make sure we show the message even when it is a dummy span.
        err.note(&span_msg);
        err.note("(no span available)");
    }
    // Show help messages.
    if !helps.is_empty() {
        // Add visual separator before backtrace.
        helps.last_mut().unwrap().1.push_str("\n");
        for (span_data, help) in helps {
            if let Some(span_data) = span_data {
                err.span_help(span_data.span(), &help);
            } else {
                err.help(&help);
            }
        }
    }
    // Add backtrace
    for (idx, frame_info) in stacktrace.iter().enumerate() {
        let is_local = frame_info.instance.def_id().is_local();
        // No span for non-local frames and the first frame (which is the error site).
        if is_local && idx > 0 {
            err.span_note(frame_info.span, &frame_info.to_string());
        } else {
            err.note(&frame_info.to_string());
        }
    }

    err.emit();
}

thread_local! {
    static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
}

/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
/// The diagnostic will be emitted after the current interpreter step is finished.
pub fn register_diagnostic(e: NonHaltingDiagnostic) {
    DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
}

/// Remember enough about the topmost frame so that we can restore the stack
/// after a step was taken.
pub struct TopFrameInfo<'tcx> {
    stack_size: usize,
    instance: Option<ty::Instance<'tcx>>,
    span: Span,
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> {
        // Ensure we have no lingering diagnostics.
        DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));

        let this = self.eval_context_ref();
        if this.active_thread_stack().is_empty() {
            // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics).
            return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
        }
        let frame = this.frame();

        TopFrameInfo {
            stack_size: this.active_thread_stack().len(),
            instance: Some(frame.instance),
            span: frame.current_span(),
        }
    }

    /// Emit all diagnostics that were registed with `register_diagnostics`
    fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) {
        let this = self.eval_context_ref();
        DIAGNOSTICS.with(|diagnostics| {
            let mut diagnostics = diagnostics.borrow_mut();
            if diagnostics.is_empty() {
                return;
            }
            // We need to fix up the stack trace, because the machine has already
            // stepped to the next statement.
            let mut stacktrace = this.generate_stacktrace();
            // Remove newly pushed frames.
            while stacktrace.len() > info.stack_size {
                stacktrace.remove(0);
            }
            // Add popped frame back.
            if stacktrace.len() < info.stack_size {
                assert!(
                    stacktrace.len() == info.stack_size - 1,
                    "we should never pop more than one frame at once"
                );
                let frame_info = FrameInfo {
                    instance: info.instance.unwrap(),
                    span: info.span,
                    lint_root: None,
                };
                stacktrace.insert(0, frame_info);
            } else if let Some(instance) = info.instance {
                // Adjust topmost frame.
                stacktrace[0].span = info.span;
                assert_eq!(
                    stacktrace[0].instance, instance,
                    "we should not pop and push a frame in one step"
                );
            }

            let stacktrace = prune_stacktrace(this, stacktrace);

            // Show diagnostics.
            for e in diagnostics.drain(..) {
                use NonHaltingDiagnostic::*;
                let msg = match e {
                    CreatedPointerTag(tag) => format!("created tag {:?}", tag),
                    PoppedPointerTag(item, tag) =>
                        match tag {
                            None =>
                                format!(
                                    "popped tracked tag for item {:?} due to deallocation",
                                    item
                                ),
                            Some((tag, access)) => {
                                format!(
                                    "popped tracked tag for item {:?} due to {:?} access for {:?}",
                                    item, access, tag
                                )
                            }
                        },
                    CreatedCallId(id) => format!("function call with id {}", id),
                    CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id),
                    FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id),
                    RejectedIsolatedOp(ref op) =>
                        format!("{} was made to return an error due to isolation", op),
                };

                let (title, diag_level) = match e {
                    RejectedIsolatedOp(_) =>
                        ("operation rejected by isolation", DiagLevel::Warning),
                    _ => ("tracking was triggered", DiagLevel::Note),
                };

                report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace);
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::MulAssign;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is a list of numbers, position is a list of numbers.
pub struct DimensionN<T = Data>(PhantomData<T>);

impl<T> Construct for DimensionN<T> {
    fn new() -> DimensionN<T> { DimensionN(PhantomData) }
}

impl Count<Vec<usize>> for DimensionN<Data> {
    type N = usize;
    fn count(&self, dim: &Vec<usize>) -> usize {
        let mut prod = 1;
        for i in 0..dim.len() {
            prod *= dim[i];
        }
        prod
    }
}

impl Count<Vec<BigUint>> for DimensionN<Data> {
    type N = BigUint;
    fn count(&self, dim: &Vec<BigUint>) -> BigUint {
        let mut prod: BigUint = 1u64.into();
        for i in 0..dim.len() {
            prod *= &dim[i];
        }
        prod
    }
}

impl<T, U>
Count<Vec<U>> for DimensionN<Of<T>>
    where
        T: Construct + Count<U>,
        <T as Count<U>>::N: From<usize> + MulAssign,
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &Vec<U>) -> Self::N {
        let of: T = Construct::new();
        let mut prod: Self::N = 1usize.into();
        for i in 0..dim.len() {
            prod *= of.count(&dim[i]);
        }
        prod
    }
}

impl Zero<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn zero(&self, dim: &Vec<usize>) -> Vec<usize> {
        vec![0; dim.len()]
    }
}

impl<T, U, V>
Zero<Vec<U>, Vec<V>>
for DimensionN<Of<T>>
    where T: Construct + Count<U> + ToPos<U, V> + Zero<U, V>
{
    fn zero(&self, dim: &Vec<U>) -> Vec<V> {
        let of: T = Construct::new();
        let mut v = Vec::with_capacity(dim.len());
        for i in 0..dim.len() {
            v.push(of.zero(&dim[i]));
        }
        v
    }
}

impl ToIndex<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn to_index(&self, dim: &Vec<usize>, pos: &Vec<usize>) -> usize {
        let mut dim_index = 0;
        for i in (0..dim.len()).rev() {
            dim_index = dim_index * dim[i] + pos[i];
        }
        dim_index
    }
}

impl<T, U, V>
ToIndex<Vec<U>, Vec<V>> for DimensionN<Of<T>>
    where T: Construct + Count<U, N = usize> + ToIndex<U, V>
{
    fn to_index(
        &self,
        dim: &Vec<U>,
        pos: &Vec<V>
    ) -> usize {
        let of: T = Construct::new();
        let mut dim_index = 0;
        for i in (0..dim.len()).rev() {
            dim_index = dim_index * of.count(&dim[i])
                      + of.to_index(&dim[i], &pos[i]);
        }
        dim_index
    }
}

impl ToPos<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn to_pos(&self, dim: &Vec<usize>, index: usize, pos: &mut Vec<usize>) {
        unsafe { pos.set_len(0); }
        let mut prod = self.count(dim);
        for _ in 0..dim.len() {
            pos.push(0);
        }
        let mut dim_index = index;
        for i in (0..dim.len()).rev() {
            prod /= dim[i];
            let p_i = dim_index / prod;
            *pos.get_mut(i).unwrap() = p_i;
            dim_index -= p_i * prod;
        }
    }
}

impl<T, U, V>
ToPos<Vec<U>, Vec<V>>
for DimensionN<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &Vec<U>,
        index: usize,
        pos: &mut Vec<V>
    ) {
        let of: T = Construct::new();
        let mut prod = self.count(dim);
        let mut dim_index = index;
        for (i, p) in pos.iter_mut().enumerate().rev() {
            prod /= of.count(&dim[i]);
            let p_i = dim_index / prod;
            of.to_pos(&dim[i], p_i, p);
            dim_index -= p_i * prod;
        }
    }
}

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

    #[test]
    fn features() {
        is_complete::<DimensionN, Vec<usize>, Vec<usize>>();
        is_complete::<DimensionN<Of<Pair>>, Vec<usize>,
            Vec<(usize, usize)>>();
    }

    #[test]
    fn data() {
        let x: DimensionN = Construct::new();
        let ref dim = vec![3, 3];
        assert_eq!(x.count(dim), 9);
        assert_eq!(x.to_index(dim, &vec![0, 0]), 0);
        assert_eq!(x.to_index(dim, &vec![1, 0]), 1);
        assert_eq!(x.to_index(dim, &vec![0, 1]), 3);
        let mut new_pos = vec![0, 0];
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(&new_pos, &[0, 1]);
    }

    #[test]
    fn of() {
        let x: DimensionN<Of<Pair>> = Construct::new();
        let ref dim = vec![3, 4];
        assert_eq!(x.count(dim), 18);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 1)]), 0);
        assert_eq!(x.to_index(dim, &vec![(0, 2), (0, 1)]), 1);
        assert_eq!(x.to_index(dim, &vec![(1, 2), (0, 1)]), 2);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3);
        let mut pos = vec![(0, 0), (0, 0)];
        x.to_pos(dim, 3, &mut pos);
        assert_eq!(pos[0], (0, 1));
        assert_eq!(pos[1], (0, 2));
    }

    #[test]
    fn zero() {
        let x: DimensionN = Construct::new();
        let ref dim = vec![2; 3];
        assert_eq!(x.zero(dim), vec![0; 3]);
    }
}
<commit_msg>Impl `Zero<Vec<BigUint>, Vec<BigUint>>` for `DimensionN`<commit_after>use std::marker::PhantomData;
use std::ops::MulAssign;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is a list of numbers, position is a list of numbers.
pub struct DimensionN<T = Data>(PhantomData<T>);

impl<T> Construct for DimensionN<T> {
    fn new() -> DimensionN<T> { DimensionN(PhantomData) }
}

impl Count<Vec<usize>> for DimensionN<Data> {
    type N = usize;
    fn count(&self, dim: &Vec<usize>) -> usize {
        let mut prod = 1;
        for i in 0..dim.len() {
            prod *= dim[i];
        }
        prod
    }
}

impl Count<Vec<BigUint>> for DimensionN<Data> {
    type N = BigUint;
    fn count(&self, dim: &Vec<BigUint>) -> BigUint {
        let mut prod: BigUint = 1u64.into();
        for i in 0..dim.len() {
            prod *= &dim[i];
        }
        prod
    }
}

impl<T, U>
Count<Vec<U>> for DimensionN<Of<T>>
    where
        T: Construct + Count<U>,
        <T as Count<U>>::N: From<usize> + MulAssign,
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &Vec<U>) -> Self::N {
        let of: T = Construct::new();
        let mut prod: Self::N = 1usize.into();
        for i in 0..dim.len() {
            prod *= of.count(&dim[i]);
        }
        prod
    }
}

impl Zero<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn zero(&self, dim: &Vec<usize>) -> Vec<usize> {
        vec![0; dim.len()]
    }
}

impl Zero<Vec<BigUint>, Vec<BigUint>> for DimensionN<Data> {
    fn zero(&self, dim: &Vec<BigUint>) -> Vec<BigUint> {
        vec![0usize.into(); dim.len()]
    }
}

impl<T, U, V>
Zero<Vec<U>, Vec<V>>
for DimensionN<Of<T>>
    where T: Construct + Count<U> + ToPos<U, V> + Zero<U, V>
{
    fn zero(&self, dim: &Vec<U>) -> Vec<V> {
        let of: T = Construct::new();
        let mut v = Vec::with_capacity(dim.len());
        for i in 0..dim.len() {
            v.push(of.zero(&dim[i]));
        }
        v
    }
}

impl ToIndex<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn to_index(&self, dim: &Vec<usize>, pos: &Vec<usize>) -> usize {
        let mut dim_index = 0;
        for i in (0..dim.len()).rev() {
            dim_index = dim_index * dim[i] + pos[i];
        }
        dim_index
    }
}

impl<T, U, V>
ToIndex<Vec<U>, Vec<V>> for DimensionN<Of<T>>
    where T: Construct + Count<U, N = usize> + ToIndex<U, V>
{
    fn to_index(
        &self,
        dim: &Vec<U>,
        pos: &Vec<V>
    ) -> usize {
        let of: T = Construct::new();
        let mut dim_index = 0;
        for i in (0..dim.len()).rev() {
            dim_index = dim_index * of.count(&dim[i])
                      + of.to_index(&dim[i], &pos[i]);
        }
        dim_index
    }
}

impl ToPos<Vec<usize>, Vec<usize>> for DimensionN<Data> {
    fn to_pos(&self, dim: &Vec<usize>, index: usize, pos: &mut Vec<usize>) {
        unsafe { pos.set_len(0); }
        let mut prod = self.count(dim);
        for _ in 0..dim.len() {
            pos.push(0);
        }
        let mut dim_index = index;
        for i in (0..dim.len()).rev() {
            prod /= dim[i];
            let p_i = dim_index / prod;
            *pos.get_mut(i).unwrap() = p_i;
            dim_index -= p_i * prod;
        }
    }
}

impl<T, U, V>
ToPos<Vec<U>, Vec<V>>
for DimensionN<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &Vec<U>,
        index: usize,
        pos: &mut Vec<V>
    ) {
        let of: T = Construct::new();
        let mut prod = self.count(dim);
        let mut dim_index = index;
        for (i, p) in pos.iter_mut().enumerate().rev() {
            prod /= of.count(&dim[i]);
            let p_i = dim_index / prod;
            of.to_pos(&dim[i], p_i, p);
            dim_index -= p_i * prod;
        }
    }
}

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

    #[test]
    fn features() {
        is_complete::<DimensionN, Vec<usize>, Vec<usize>>();
        is_complete::<DimensionN<Of<Pair>>, Vec<usize>,
            Vec<(usize, usize)>>();
    }

    #[test]
    fn data() {
        let x: DimensionN = Construct::new();
        let ref dim = vec![3, 3];
        assert_eq!(x.count(dim), 9);
        assert_eq!(x.to_index(dim, &vec![0, 0]), 0);
        assert_eq!(x.to_index(dim, &vec![1, 0]), 1);
        assert_eq!(x.to_index(dim, &vec![0, 1]), 3);
        let mut new_pos = vec![0, 0];
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(&new_pos, &[0, 1]);
    }

    #[test]
    fn of() {
        let x: DimensionN<Of<Pair>> = Construct::new();
        let ref dim = vec![3, 4];
        assert_eq!(x.count(dim), 18);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 1)]), 0);
        assert_eq!(x.to_index(dim, &vec![(0, 2), (0, 1)]), 1);
        assert_eq!(x.to_index(dim, &vec![(1, 2), (0, 1)]), 2);
        assert_eq!(x.to_index(dim, &vec![(0, 1), (0, 2)]), 3);
        let mut pos = vec![(0, 0), (0, 0)];
        x.to_pos(dim, 3, &mut pos);
        assert_eq!(pos[0], (0, 1));
        assert_eq!(pos[1], (0, 2));
    }

    #[test]
    fn zero() {
        let x: DimensionN = Construct::new();
        let ref dim = vec![2; 3];
        assert_eq!(x.zero(dim), vec![0; 3]);
    }
}
<|endoftext|>


<commit_before>
#![allow(unused)]
include!(concat!(env!("OUT_DIR"), "/entry_capnp.rs"));

use std;
use std::io;

use capnp;

pub fn write_capnp<W: io::Write>(
    to: &mut W,
    current: &::FileDetails,
    size: u64) -> io::Result<()> {

    let mut message = capnp::message::Builder::new_default();
    {
        let mut entry = message.init_root::<entry::Builder>();
        entry.set_magic(0x0100C1C1);
        entry.set_len(size);
        entry.set_atime(current.atime);
        entry.set_mtime(current.mtime);
        entry.set_ctime(current.ctime);
        entry.set_btime(current.btime);

        {
            let mut type_ = entry.borrow().get_type();

            // TODO: other file types / proper tracking of this
            match size {
                0 => type_.set_directory(()),
                _ => type_.set_normal(()),
            }
        }

        {
            let mut posix = entry.borrow().get_ownership().init_posix();
            {
                let mut user = posix.borrow().init_user();
                user.set_id(current.uid);
                user.set_name(current.user_name.as_str());
            }
            {
                let mut group = posix.borrow().init_group();
                group.set_id(current.gid);
                group.set_name(current.group_name.as_str());
            }

            // TODO: mode
        }
        {
            let mut paths = entry.init_paths(current.depth + 1);
            for (i, path) in current.path.iter().enumerate() {
                assert!(i < std::u32::MAX as usize);
                paths.set(i as u32, path.as_str());
            }
        }

    }
    capnp::serialize::write_message(to, &message)
}
<commit_msg>write capnp in struct order, as recommended<commit_after>
#![allow(unused)]
include!(concat!(env!("OUT_DIR"), "/entry_capnp.rs"));

use std;
use std::io;

use capnp;

pub fn write_capnp<W: io::Write>(
    to: &mut W,
    current: &::FileDetails,
    size: u64) -> io::Result<()> {

    let mut message = capnp::message::Builder::new_default();
    {
        let mut entry = message.init_root::<entry::Builder>();
        entry.set_magic(0x0100C1C1);
        entry.set_len(size);

        {
            let mut paths = entry.borrow().init_paths(current.depth + 1);
            for (i, path) in current.path.iter().enumerate() {
                assert!(i < std::u32::MAX as usize);
                paths.set(i as u32, path.as_str());
            }
        }

        entry.set_atime(current.atime);
        entry.set_mtime(current.mtime);
        entry.set_ctime(current.ctime);
        entry.set_btime(current.btime);

        {
            let mut posix = entry.borrow().get_ownership().init_posix();
            {
                let mut user = posix.borrow().init_user();
                user.set_id(current.uid);
                user.set_name(current.user_name.as_str());
            }
            {
                let mut group = posix.borrow().init_group();
                group.set_id(current.gid);
                group.set_name(current.group_name.as_str());
            }

            // TODO: mode
        }

        {
            let mut type_ = entry.borrow().get_type();

            // TODO: other file types / proper tracking of this
            match size {
                0 => type_.set_directory(()),
                _ => type_.set_normal(()),
            }
        }
    }
    capnp::serialize::write_message(to, &message)
}
<|endoftext|>


<commit_before>use glutin;
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin::GlContext;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Zombie shooter");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        glutin::get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(monitor)
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat,
      DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0)
    }
  }
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Render,
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn poll_events(&mut self) -> Option<GameStatus>;

  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);

  fn get_viewport_size(&mut self) -> (u32, u32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
      .swap_buffers()
      .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (u32, u32) {
    self.window
      .get_inner_size_pixels()
      .unwrap_or((RESOLUTION_X, RESOLUTION_Y))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> Option<GameStatus> {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, Closed, MouseMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status: Option<GameStatus> = None;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => Some(GameStatus::Quit),
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => { controls.zoom_out(); None },
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              controls.move_map_up();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              controls.move_map_down();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              controls.stop_map_y();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              controls.move_map_left();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              controls.move_map_right();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              controls.stop_map_x();
              None
            },
            _ => None,
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            None
          },
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            None
          },
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            None
          },
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            None
          },
          MouseMoved { position, .. } => {
            *m_pos = position;
            None
          },
          Closed => Some(GameStatus::Quit),
          Resized(_, _) => {gfx_window_glutin::update_views(w, m_rtv, m_dsv); Some(GameStatus::Quit)},
          _ => None,
        }
      } else {
        None
      };
    });
    game_status
  }
}

<commit_msg>Remove extra map movement calls<commit_after>use glutin;
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin::GlContext;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Zombie shooter");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        glutin::get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(monitor)
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat,
      DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0)
    }
  }
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Render,
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn poll_events(&mut self) -> Option<GameStatus>;

  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);

  fn get_viewport_size(&mut self) -> (u32, u32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
      .swap_buffers()
      .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (u32, u32) {
    self.window
      .get_inner_size_pixels()
      .unwrap_or((RESOLUTION_X, RESOLUTION_Y))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> Option<GameStatus> {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, Closed, MouseMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status: Option<GameStatus> = None;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => Some(GameStatus::Quit),
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => { controls.zoom_out(); None },
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              controls.move_map_left();
              None
            },
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              None
            },
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              None
            },
            _ => None,
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            None
          },
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            None
          },
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            None
          },
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            None
          },
          MouseMoved { position, .. } => {
            *m_pos = position;
            None
          },
          Closed => Some(GameStatus::Quit),
          Resized(_, _) => {gfx_window_glutin::update_views(w, m_rtv, m_dsv); Some(GameStatus::Quit)},
          _ => None,
        }
      } else {
        None
      };
    });
    game_status
  }
}

<|endoftext|>


<commit_before>use std::marker;
use std::collections::BitVec;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::GetAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: BitVec,
    generation: usize,
    _etype: marker::PhantomData<Ty>,
}

impl<Ty, Ix> Vf2State<Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self
    {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
            _etype: marker::PhantomData,
        };
        for _ in (0..c0) {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
            self.out_size += 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
            self.ins_size += 1;
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
            self.out_size -= 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
            self.ins_size -= 1;
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ix, Ty>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ix: IndexType,
    Ty: EdgeType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ix, Ty>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ix: IndexType,
        Ty: EdgeType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.mapping[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            //
            // Note: We want to check the lookahead measures here if we can,
            // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
            // R_in: Same with Tin
            // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
            //      Ñ is G0 - M - Tin - Tout
            // last attempt to add these did not speed up any of the testcases
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check counts in Tin/Tout
            if st[0].out_size == st[0].out_size ||
               st[1].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<commit_msg>Fix inconsistent type param order<commit_after>use std::marker;
use std::collections::BitVec;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::GetAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: BitVec,
    generation: usize,
    _etype: marker::PhantomData<Ty>,
}

impl<Ty, Ix> Vf2State<Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self
    {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
            _etype: marker::PhantomData,
        };
        for _ in (0..c0) {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if <Ty as EdgeType>::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool
    {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
            self.out_size += 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
            self.ins_size += 1;
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
            self.out_size -= 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
            self.ins_size -= 1;
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !<Ty as EdgeType>::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return **true** if the graphs **g0** and **g1** are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ty, Ix>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool where
    Ty: EdgeType,
    Ix: IndexType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ty, Ix>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool> where
        Ty: EdgeType,
        Ix: IndexType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            /*
            print!("Mapping state: ");
            for (index, nmap) in st.mapping[0].iter().enumerate() {
                if *nmap == end {
                    continue;
                }
                print!("{} => {}, ", index, nmap.index());
            }
            println!("{} => {}", nx.index(), mx.index());
            */

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            //
            // Note: We want to check the lookahead measures here if we can,
            // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
            // R_in: Same with Tin
            // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
            //      Ñ is G0 - M - Tin - Tout
            // last attempt to add these did not speed up any of the testcases
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check counts in Tin/Tout
            if st[0].out_size == st[0].out_size ||
               st[1].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<|endoftext|>


<commit_before>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**c) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>libstd: add a method to generate random bytestrings.<commit_after>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;

    /*
    Method: gen_bytes

    Return a random byte string.
    */
    fn gen_bytes(len: uint) -> [u8];
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**c) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let v = [];
            let i = 0u;
            while i < len {
                let n = rustrt::rand_next(**c) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use std::error::Error;

//Following semver here
#[derive(Clone, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<commit_msg>Made the methods public<commit_after>use std::error::Error;

//Following semver here
#[derive(Clone, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    pub fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    pub fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    pub fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<|endoftext|>