<commit_before>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::{self, def_id::DefId};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};

use super::{
    Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
    EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
};

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Test if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Insert new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Remove entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Return data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Return a reference to entry `k`.  If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Return a mutable reference to entry `k`.  If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'a, 'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer.  This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory.  A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra: Default;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag, Self::MemoryExtra>;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done).  In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    fn find_foreign_static(
        def_id: DefId,
        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
        memory_extra: &Self::MemoryExtra,
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;

    /// Called to turn an allocation obtained from the `tcx` into one that has
    /// the right type for this machine.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    fn adjust_static_allocation<'b>(
        alloc: &'b Allocation,
        memory_extra: &Self::MemoryExtra,
    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;

    /// Called for all binary operations on integer(-like) types when one operand is a pointer
    /// value, and for the `Offset` operation that is inherently about pointers.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn ptr_op(
        ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: Scalar<Self::PointerTag>,
        left_layout: TyLayout<'tcx>,
        right: Scalar<Self::PointerTag>,
        right_layout: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx>;

    /// Add the tag for a newly allocated pointer.
    fn tag_new_allocation(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        kind: MemoryKind<Self::MemoryKinds>,
    ) -> Pointer<Self::PointerTag>;

    /// Executed when evaluating the `*` operator: Following a reference.
    /// This has the chance to adjust the tag.  It should not change anything else!
    /// `mutability` can be `None` in case a raw ptr is being dereferenced.
    #[inline]
    fn tag_dereference(
        _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
        place: MPlaceTy<'tcx, Self::PointerTag>,
        _mutability: Option<hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
        Ok(place.ptr)
    }

    /// Execute a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
    ) -> EvalResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        extra: Self::FrameExtra,
    ) -> EvalResult<'tcx>;
}
<commit_msg>Add missing 'static bound for the Machine  trait<commit_after>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::{self, def_id::DefId};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};

use super::{
    Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
    EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
};

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Test if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Insert new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Remove entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Return data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Return a reference to entry `k`.  If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Return a mutable reference to entry `k`.  If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'a, 'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer.  This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory.  A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra: Default;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag, Self::MemoryExtra> + 'static;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done).  In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    fn find_foreign_static(
        def_id: DefId,
        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
        memory_extra: &Self::MemoryExtra,
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;

    /// Called to turn an allocation obtained from the `tcx` into one that has
    /// the right type for this machine.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    fn adjust_static_allocation<'b>(
        alloc: &'b Allocation,
        memory_extra: &Self::MemoryExtra,
    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;

    /// Called for all binary operations on integer(-like) types when one operand is a pointer
    /// value, and for the `Offset` operation that is inherently about pointers.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn ptr_op(
        ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: Scalar<Self::PointerTag>,
        left_layout: TyLayout<'tcx>,
        right: Scalar<Self::PointerTag>,
        right_layout: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx>;

    /// Add the tag for a newly allocated pointer.
    fn tag_new_allocation(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        kind: MemoryKind<Self::MemoryKinds>,
    ) -> Pointer<Self::PointerTag>;

    /// Executed when evaluating the `*` operator: Following a reference.
    /// This has the chance to adjust the tag.  It should not change anything else!
    /// `mutability` can be `None` in case a raw ptr is being dereferenced.
    #[inline]
    fn tag_dereference(
        _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
        place: MPlaceTy<'tcx, Self::PointerTag>,
        _mutability: Option<hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
        Ok(place.ptr)
    }

    /// Execute a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> EvalResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
    ) -> EvalResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        extra: Self::FrameExtra,
    ) -> EvalResult<'tcx>;
}
<|endoftext|>


<commit_before>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    path::{Path, PathBuf},
    sync::Mutex,
};

use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length = file[literal_start..].find("]]").unwrap();
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };
        panic!(
            "\n
error: expect test failed{}
  --> {}:{}:{}
{}
Expect:
----
{}
----

Actual:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual
        )
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_expect_macro() {
        let empty = expect![[]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 241,
                column: 21,
                data: "",
            }
        "#]]
        .assert_debug_eq(&empty);

        let expect = expect![["
            hello
            world
        "]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 252,
                column: 22,
                data: "\n            hello\n            world\n        ",
            }
        "#]]
        .assert_debug_eq(&expect);
    }

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<commit_msg>Update crates/expect/src/lib.rs<commit_after>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    path::{Path, PathBuf},
    sync::Mutex,
};

use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length = file[literal_start..].find("]]").unwrap();
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };
        println!(
            "\n
error: expect test failed{}
  --> {}:{}:{}
{}
Expect:
----
{}
----

Actual:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        std::panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_expect_macro() {
        let empty = expect![[]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 241,
                column: 21,
                data: "",
            }
        "#]]
        .assert_debug_eq(&empty);

        let expect = expect![["
            hello
            world
        "]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 252,
                column: 22,
                data: "\n            hello\n            world\n        ",
            }
        "#]]
        .assert_debug_eq(&expect);
    }

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<|endoftext|>


<commit_before>//! In rust-analyzer, syntax trees are transient objects.
//!
//! That means that we create trees when we need them, and tear them down to
//! save memory. In this architecture, hanging on to a particular syntax node
//! for a long time is ill-advisable, as that keeps the whole tree resident.
//!
//! Instead, we provide a [`SyntaxNodePtr`] type, which stores information about
//! *location* of a particular syntax node in a tree. Its a small type which can
//! be cheaply stored, and which can be resolved to a real [`SyntaxNode`] when
//! necessary.

use std::{
    hash::{Hash, Hasher},
    iter::successors,
    marker::PhantomData,
};

use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};

/// A pointer to a syntax node inside a file. It can be used to remember a
/// specific node across reparses of the same file.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntaxNodePtr {
    // Don't expose this field further. At some point, we might want to replace
    // range with node id.
    pub(crate) range: TextRange,
    kind: SyntaxKind,
}

impl SyntaxNodePtr {
    pub fn new(node: &SyntaxNode) -> SyntaxNodePtr {
        SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
        assert!(root.parent().is_none());
        successors(Some(root.clone()), |node| {
            node.children().find(|it| it.text_range().contains_range(self.range))
        })
        .find(|it| it.text_range() == self.range && it.kind() == self.kind)
        .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
    }

    pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
        if !N::can_cast(self.kind) {
            return None;
        }
        Some(AstPtr { raw: self, _ty: PhantomData })
    }
}

/// Like `SyntaxNodePtr`, but remembers the type of node
#[derive(Debug)]
pub struct AstPtr<N: AstNode> {
    raw: SyntaxNodePtr,
    _ty: PhantomData<fn() -> N>,
}

impl<N: AstNode> Clone for AstPtr<N> {
    fn clone(&self) -> AstPtr<N> {
        AstPtr { raw: self.raw.clone(), _ty: PhantomData }
    }
}

impl<N: AstNode> Eq for AstPtr<N> {}

impl<N: AstNode> PartialEq for AstPtr<N> {
    fn eq(&self, other: &AstPtr<N>) -> bool {
        self.raw == other.raw
    }
}

impl<N: AstNode> Hash for AstPtr<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw.hash(state)
    }
}

impl<N: AstNode> AstPtr<N> {
    pub fn new(node: &N) -> AstPtr<N> {
        AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> N {
        let syntax_node = self.raw.to_node(root);
        N::cast(syntax_node).unwrap()
    }

    pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
        self.raw.clone()
    }

    pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
        if !U::can_cast(self.raw.kind) {
            return None;
        }
        Some(AstPtr { raw: self.raw, _ty: PhantomData })
    }
}

impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
    fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
        ptr.raw
    }
}

#[test]
fn test_local_syntax_ptr() {
    use crate::{ast, AstNode, SourceFile};

    let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
    let field = file.syntax().descendants().find_map(ast::RecordField::cast).unwrap();
    let ptr = SyntaxNodePtr::new(field.syntax());
    let field_syntax = ptr.to_node(file.syntax());
    assert_eq!(field.syntax(), &field_syntax);
}
<commit_msg>Document perf characteristic of to_node<commit_after>//! In rust-analyzer, syntax trees are transient objects.
//!
//! That means that we create trees when we need them, and tear them down to
//! save memory. In this architecture, hanging on to a particular syntax node
//! for a long time is ill-advisable, as that keeps the whole tree resident.
//!
//! Instead, we provide a [`SyntaxNodePtr`] type, which stores information about
//! *location* of a particular syntax node in a tree. Its a small type which can
//! be cheaply stored, and which can be resolved to a real [`SyntaxNode`] when
//! necessary.

use std::{
    hash::{Hash, Hasher},
    iter::successors,
    marker::PhantomData,
};

use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};

/// A pointer to a syntax node inside a file. It can be used to remember a
/// specific node across reparses of the same file.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SyntaxNodePtr {
    // Don't expose this field further. At some point, we might want to replace
    // range with node id.
    pub(crate) range: TextRange,
    kind: SyntaxKind,
}

impl SyntaxNodePtr {
    pub fn new(node: &SyntaxNode) -> SyntaxNodePtr {
        SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
    }

    /// "Dereference" the pointer to get the node it points to.
    ///
    /// Panics if node is not found, so make sure that `root` syntax tree is
    /// equivalent (is build from the same text) to the tree which was
    /// originally used to get this [`SyntaxNodePtr`].
    ///
    /// The complexity is linear in the depth of the tree and logarithmic in
    /// tree width. As most trees are shallow, thinking about this as
    /// `O(log(N))` in the size of the tree is not too wrong!
    pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode {
        assert!(root.parent().is_none());
        successors(Some(root.clone()), |node| {
            node.children().find(|it| it.text_range().contains_range(self.range))
        })
        .find(|it| it.text_range() == self.range && it.kind() == self.kind)
        .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
    }

    pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
        if !N::can_cast(self.kind) {
            return None;
        }
        Some(AstPtr { raw: self, _ty: PhantomData })
    }
}

/// Like `SyntaxNodePtr`, but remembers the type of node
#[derive(Debug)]
pub struct AstPtr<N: AstNode> {
    raw: SyntaxNodePtr,
    _ty: PhantomData<fn() -> N>,
}

impl<N: AstNode> Clone for AstPtr<N> {
    fn clone(&self) -> AstPtr<N> {
        AstPtr { raw: self.raw.clone(), _ty: PhantomData }
    }
}

impl<N: AstNode> Eq for AstPtr<N> {}

impl<N: AstNode> PartialEq for AstPtr<N> {
    fn eq(&self, other: &AstPtr<N>) -> bool {
        self.raw == other.raw
    }
}

impl<N: AstNode> Hash for AstPtr<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw.hash(state)
    }
}

impl<N: AstNode> AstPtr<N> {
    pub fn new(node: &N) -> AstPtr<N> {
        AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
    }

    pub fn to_node(&self, root: &SyntaxNode) -> N {
        let syntax_node = self.raw.to_node(root);
        N::cast(syntax_node).unwrap()
    }

    pub fn syntax_node_ptr(&self) -> SyntaxNodePtr {
        self.raw.clone()
    }

    pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
        if !U::can_cast(self.raw.kind) {
            return None;
        }
        Some(AstPtr { raw: self.raw, _ty: PhantomData })
    }
}

impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
    fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
        ptr.raw
    }
}

#[test]
fn test_local_syntax_ptr() {
    use crate::{ast, AstNode, SourceFile};

    let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
    let field = file.syntax().descendants().find_map(ast::RecordField::cast).unwrap();
    let ptr = SyntaxNodePtr::new(field.syntax());
    let field_syntax = ptr.to_node(file.syntax());
    assert_eq!(field.syntax(), &field_syntax);
}
<|endoftext|>


<commit_before>//! # rustup_component_installer
//!
//! Installs rustup components.
//!

#[cfg(test)]
#[path = "./rustup_component_installer_test.rs"]
mod rustup_component_installer_test;

use crate::command;
use crate::toolchain::wrap_command;
use crate::types::InstallRustupComponentInfo;
use std::process::Command;

pub(crate) fn is_installed(toolchain: &Option<String>, binary: &str, test_args: &[String]) -> bool {
    let mut command_struct = match toolchain {
        Some(ref toolchain_string) => {
            let command_spec = wrap_command(toolchain_string, binary, &None);
            let mut cmd = Command::new(command_spec.command);

            let args_vec = command_spec.args.unwrap();
            for arg in args_vec.iter() {
                cmd.arg(arg);
            }

            cmd
        }
        None => Command::new(binary),
    };

    let result = command_struct.args(test_args).output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);

            if exit_code != 0 {
                false
            } else {
                true
            }
        }
        Err(error) => {
            debug!(
                "Unable to check if crate is installed: {} {:#?}",
                binary, &error
            );
            false
        }
    }
}

pub(crate) fn invoke_rustup_install(
    toolchain: &Option<String>,
    info: &InstallRustupComponentInfo,
) -> bool {
    let mut command_spec = Command::new("rustup");
    command_spec.arg("component");
    command_spec.arg("add");

    match toolchain {
        Some(ref toolchain_string) => {
            command_spec.arg("--toolchain");
            command_spec.arg(toolchain_string);
        }
        None => {}
    };

    let result = command_spec.arg(&info.rustup_component_name).output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);

            if exit_code != 0 {
                debug!(
                    "Failed to add component: {} via rustup",
                    &info.rustup_component_name
                );

                false
            } else {
                debug!(
                    "Component: {} added via rustup",
                    &info.rustup_component_name
                );

                true
            }
        }
        Err(error) => {
            debug!(
                "Failed to add component: {} via rustup, error: {:#?}",
                &info.rustup_component_name, &error
            );
            false
        }
    }
}

pub(crate) fn install(
    toolchain: &Option<String>,
    info: &InstallRustupComponentInfo,
    validate: bool,
) -> bool {
    let mut installed = match info.binary {
        Some(ref binary) => match info.test_arg {
            Some(ref test_arg) => is_installed(&toolchain, binary, test_arg),
            None => false,
        },
        None => false,
    };

    if !installed {
        debug!(
            "Rustup Component: {} not installed.",
            &info.rustup_component_name
        );

        installed = invoke_rustup_install(&toolchain, &info);

        if validate && !installed {
            error!(
                "Failed to add rustup component: {}",
                &info.rustup_component_name
            );
        }

        installed
    } else {
        true
    }
}
<commit_msg>additional debug logging<commit_after>//! # rustup_component_installer
//!
//! Installs rustup components.
//!

#[cfg(test)]
#[path = "./rustup_component_installer_test.rs"]
mod rustup_component_installer_test;

use crate::command;
use crate::toolchain::wrap_command;
use crate::types::InstallRustupComponentInfo;
use std::process::Command;

pub(crate) fn is_installed(toolchain: &Option<String>, binary: &str, test_args: &[String]) -> bool {
    let mut command_struct = match toolchain {
        Some(ref toolchain_string) => {
            let command_spec = wrap_command(toolchain_string, binary, &None);
            let mut cmd = Command::new(command_spec.command);

            let args_vec = command_spec.args.unwrap();
            for arg in args_vec.iter() {
                cmd.arg(arg);
            }

            cmd
        }
        None => Command::new(binary),
    };

    debug!(
        "Validating installation using command: {} args: {:#?}",
        binary, &test_args
    );
    let result = command_struct.args(test_args).output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);
            debug!("Installation validation test exit code: {}", exit_code);

            if exit_code != 0 {
                false
            } else {
                true
            }
        }
        Err(error) => {
            debug!(
                "Unable to check if crate is installed: {} {:#?}",
                binary, &error
            );
            false
        }
    }
}

pub(crate) fn invoke_rustup_install(
    toolchain: &Option<String>,
    info: &InstallRustupComponentInfo,
) -> bool {
    let mut command_spec = Command::new("rustup");
    command_spec.arg("component");
    command_spec.arg("add");

    match toolchain {
        Some(ref toolchain_string) => {
            command_spec.arg("--toolchain");
            command_spec.arg(toolchain_string);
        }
        None => {}
    };

    let result = command_spec.arg(&info.rustup_component_name).output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);

            if exit_code != 0 {
                debug!(
                    "Failed to add component: {} via rustup",
                    &info.rustup_component_name
                );

                false
            } else {
                debug!(
                    "Component: {} added via rustup",
                    &info.rustup_component_name
                );

                true
            }
        }
        Err(error) => {
            debug!(
                "Failed to add component: {} via rustup, error: {:#?}",
                &info.rustup_component_name, &error
            );
            false
        }
    }
}

pub(crate) fn install(
    toolchain: &Option<String>,
    info: &InstallRustupComponentInfo,
    validate: bool,
) -> bool {
    let mut installed = match info.binary {
        Some(ref binary) => match info.test_arg {
            Some(ref test_arg) => is_installed(&toolchain, binary, test_arg),
            None => false,
        },
        None => false,
    };

    if !installed {
        debug!(
            "Rustup Component: {} not installed.",
            &info.rustup_component_name
        );

        installed = invoke_rustup_install(&toolchain, &info);

        if validate && !installed {
            error!(
                "Failed to add rustup component: {}",
                &info.rustup_component_name
            );
        }

        installed
    } else {
        true
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate bip_metainfo;
extern crate test;

#[cfg(test)]
mod benches {
    use bip_metainfo::{MetainfoFile, MetainfoBuilder, DirectAccessor};
    use test::Bencher;

    #[bench]
    fn bench_build_multi_kb_metainfo(b: &mut Bencher) {
        let file_content = vec![55u8; 10 * 1024 * 1024];

        b.iter(|| {
            let direct_accessor = DirectAccessor::new("100MBFile", &file_content);

            MetainfoBuilder::new().build_as_bytes(2, direct_accessor, |_| ()).unwrap();
        });
    }

    #[bench]
    fn bench_parse_multi_kb_metainfo(b: &mut Bencher) {
        let metainfo = include_bytes!("multi_kb.metainfo");

        b.iter(|| MetainfoFile::from_bytes(&metainfo[..]).unwrap());
    }
}<commit_msg>Fix bip_metainfo Bench<commit_after>#![feature(test)]

extern crate bip_metainfo;
extern crate test;

#[cfg(test)]
mod benches {
    use bip_metainfo::{Metainfo, MetainfoBuilder, DirectAccessor};
    use test::Bencher;

    #[bench]
    fn bench_build_multi_kb_metainfo(b: &mut Bencher) {
        let file_content = vec![55u8; 10 * 1024 * 1024];

        b.iter(|| {
            let direct_accessor = DirectAccessor::new("100MBFile", &file_content);

            MetainfoBuilder::new().build(2, direct_accessor, |_| ()).unwrap();
        });
    }

    #[bench]
    fn bench_parse_multi_kb_metainfo(b: &mut Bencher) {
        let metainfo = include_bytes!("multi_kb.metainfo");

        b.iter(|| Metainfo::from_bytes(&metainfo[..]).unwrap());
    }
}<|endoftext|>


<commit_before>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

use std;
import io::writer;
import io::writer_util;

import pipes::{port, chan};

macro_rules! move {
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
}

enum request {
    get_count,
    bytes(uint),
    stop
}

fn server(requests: port_set<request>, responses: pipes::chan<uint>) {
    let mut count = 0u;
    let mut done = false;
    while !done {
        alt requests.try_recv() {
          some(get_count) { responses.send(copy count); }
          some(bytes(b)) {
            //#error("server: received %? bytes", b);
            count += b;
          }
          none { done = true; }
          _ { }
        }
    }
    responses.send(count);
    //#error("server exiting");
}

fn run(args: &[str]) {
    let (to_parent, from_child) = pipes::stream();
    let (to_child, from_parent_) = pipes::stream();
    let from_parent = port_set();
    from_parent.add(from_parent_);

    let size = option::get(uint::from_str(args[1]));
    let workers = option::get(uint::from_str(args[2]));
    let num_bytes = 100;
    let start = std::time::precise_time_s();
    let mut worker_results = ~[];
    for uint::range(0u, workers) |i| {
        let builder = task::builder();
        vec::push(worker_results, task::future_result(builder));
        let (to_child, from_parent_) = pipes::stream();
        from_parent.add(from_parent_);
        do task::run(builder) {
            for uint::range(0u, size / workers) |_i| {
                //#error("worker %?: sending %? bytes", i, num_bytes);
                to_child.send(bytes(num_bytes));
            }
            //#error("worker %? exiting", i);
        };
    }
    do task::spawn {
        server(from_parent, to_parent);
    }

    vec::iter(worker_results, |r| { future::get(r); } );
    //#error("sending stop message");
    to_child.send(stop);
    move!{to_child};
    let result = from_child.recv();
    let end = std::time::precise_time_s();
    let elapsed = end - start;
    io::stdout().write_str(#fmt("Count is %?\n", result));
    io::stdout().write_str(#fmt("Test took %? seconds\n", elapsed));
    let thruput = ((size / workers * workers) as float) / (elapsed as float);
    io::stdout().write_str(#fmt("Throughput=%f per sec\n", thruput));
    assert result == num_bytes * size;
}

fn main(args: ~[str]) {
    let args = if os::getenv("RUST_BENCH").is_some() {
        ~["", "1000000", "10000"]
    } else if args.len() <= 1u {
        ~["", "10000", "4"]
    } else {
        copy args
    };

    #debug("%?", args);
    run(args);
}

// Treat a whole bunch of ports as one.
class box<T> {
    let mut contents: option<T>;
    new(+x: T) { self.contents = some(x); }

    fn swap(f: fn(+T) -> T) {
        let mut tmp = none;
        self.contents <-> tmp;
        self.contents = some(f(option::unwrap(tmp)));
    }

    fn unwrap() -> T {
        let mut tmp = none;
        self.contents <-> tmp;
        option::unwrap(tmp)
    }
}

class port_set<T: send> {
    let ports: box<~[pipes::streamp::server::open<T>]>;

    new() { self.ports = box(~[]); }

    fn add(+port: pipes::port<T>) {
        let pipes::port_(port) <- port;
        let mut p = none;
        port.endp <-> p;
        do self.ports.swap |ports| {
            let mut p_ = none;
            p <-> p_;
            vec::append_one(ports, option::unwrap(p_))
        }
    }

    fn try_recv() -> option<T> {
        let mut result = none;
        let mut done = false;
        while !done {
            do self.ports.swap |ports| {
                if ports.len() > 0 {
                    let old_len = ports.len();
                    let (_, m, ports) = pipes::select(ports);
                    alt m {
                      some(pipes::streamp::data(x, next)) {
                        result = some(move!{x});
                        done = true;
                        assert ports.len() == old_len - 1;
                        vec::append_one(ports, move!{next})
                      }
                      none {
                        //#error("pipe closed");
                        assert ports.len() == old_len - 1;
                        ports
                      }
                    }
                }
                else {
                    //#error("no more pipes");
                    done = true;
                    ~[]
                }
            }
        }
        result
    }

    fn recv() -> T {
        option::unwrap(self.try_recv())
    }
}
<commit_msg>Faster select. This version gives us about a 4x speedup.<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

use std;
import io::writer;
import io::writer_util;

import pipes::{port, chan};

macro_rules! move {
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
}

enum request {
    get_count,
    bytes(uint),
    stop
}

fn server(requests: port_set<request>, responses: pipes::chan<uint>) {
    let mut count = 0u;
    let mut done = false;
    while !done {
        alt requests.try_recv() {
          some(get_count) { responses.send(copy count); }
          some(bytes(b)) {
            //#error("server: received %? bytes", b);
            count += b;
          }
          none { done = true; }
          _ { }
        }
    }
    responses.send(count);
    //#error("server exiting");
}

fn run(args: &[str]) {
    let (to_parent, from_child) = pipes::stream();
    let (to_child, from_parent_) = pipes::stream();
    let from_parent = port_set();
    from_parent.add(from_parent_);

    let size = option::get(uint::from_str(args[1]));
    let workers = option::get(uint::from_str(args[2]));
    let num_bytes = 100;
    let start = std::time::precise_time_s();
    let mut worker_results = ~[];
    for uint::range(0u, workers) |i| {
        let builder = task::builder();
        vec::push(worker_results, task::future_result(builder));
        let (to_child, from_parent_) = pipes::stream();
        from_parent.add(from_parent_);
        do task::run(builder) {
            for uint::range(0u, size / workers) |_i| {
                //#error("worker %?: sending %? bytes", i, num_bytes);
                to_child.send(bytes(num_bytes));
            }
            //#error("worker %? exiting", i);
        };
    }
    do task::spawn {
        server(from_parent, to_parent);
    }

    vec::iter(worker_results, |r| { future::get(r); } );
    //#error("sending stop message");
    to_child.send(stop);
    move!{to_child};
    let result = from_child.recv();
    let end = std::time::precise_time_s();
    let elapsed = end - start;
    io::stdout().write_str(#fmt("Count is %?\n", result));
    io::stdout().write_str(#fmt("Test took %? seconds\n", elapsed));
    let thruput = ((size / workers * workers) as float) / (elapsed as float);
    io::stdout().write_str(#fmt("Throughput=%f per sec\n", thruput));
    assert result == num_bytes * size;
}

fn main(args: ~[str]) {
    let args = if os::getenv("RUST_BENCH").is_some() {
        ~["", "1000000", "8"]
    } else if args.len() <= 1u {
        ~["", "10000", "4"]
    } else {
        copy args
    };

    #debug("%?", args);
    run(args);
}

// Treat a whole bunch of ports as one.
class box<T> {
    let mut contents: option<T>;
    new(+x: T) { self.contents = some(x); }

    fn swap(f: fn(+T) -> T) {
        let mut tmp = none;
        self.contents <-> tmp;
        self.contents = some(f(option::unwrap(tmp)));
    }

    fn unwrap() -> T {
        let mut tmp = none;
        self.contents <-> tmp;
        option::unwrap(tmp)
    }
}

class port_set<T: send> {
    let mut ports: ~[pipes::port<T>];

    new() { self.ports = ~[]; }

    fn add(+port: pipes::port<T>) {
        vec::push(self.ports, port)
    }

    fn try_recv() -> option<T> {
        let mut result = none;
        while result == none && self.ports.len() > 0 {
            let i = pipes::wait_many(self.ports.map(|p| p.header()));
            // dereferencing an unsafe pointer nonsense to appease the
            // borrowchecker.
            alt unsafe {(*ptr::addr_of(self.ports[i])).try_recv()} {
              some(m) {
                result = some(move!{m});
              }
              none {
                // Remove this port.
                let mut ports = ~[];
                self.ports <-> ports;
                vec::consume(ports,
                             |j, x| if i != j { vec::push(self.ports, x) });
              }
            }
        }
/*
        while !done {
            do self.ports.swap |ports| {
                if ports.len() > 0 {
                    let old_len = ports.len();
                    let (_, m, ports) = pipes::select(ports);
                    alt m {
                      some(pipes::streamp::data(x, next)) {
                        result = some(move!{x});
                        done = true;
                        assert ports.len() == old_len - 1;
                        vec::append_one(ports, move!{next})
                      }
                      none {
                        //#error("pipe closed");
                        assert ports.len() == old_len - 1;
                        ports
                      }
                    }
                }
                else {
                    //#error("no more pipes");
                    done = true;
                    ~[]
                }
            }
        }
*/
        result
    }

    fn recv() -> T {
        option::unwrap(self.try_recv())
    }
}

impl private_methods/&<T: send> for pipes::port<T> {
    pure fn header() -> *pipes::packet_header unchecked {
        alt self.endp {
          some(endp) {
            endp.header()
          }
          none { fail "peeking empty stream" }
        }
    }
}<|endoftext|>


<commit_before>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::{Read, Take};
use std::thread;

fn limit<'a>(f: &'a mut File, h: &mp4parse::BoxHeader) -> Take<&'a mut File> {
    f.take(h.size - h.offset)
}

fn read_box(f: &mut File) {
    match mp4parse::read_box_header(f) {
        Some(h) => {
            match &(mp4parse::fourcc_to_string(h.name))[..] {
                "ftyp" => {
                    let mut content = limit(f, &h);
                    let ftyp = mp4parse::read_ftyp(&mut content, &h).unwrap();
                    println!("{}", ftyp);
                },
                _ => {
                    println!("{}", h);
                    mp4parse::skip_box_content(f, &h).unwrap();
                },
            }
        },
        None => (),
    }
}

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            read_box(&mut f);
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<commit_msg>Turn the outer match into an and_then().<commit_after>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::{Read, Take};
use std::thread;

fn limit<'a>(f: &'a mut File, h: &mp4parse::BoxHeader) -> Take<&'a mut File> {
    f.take(h.size - h.offset)
}

fn read_box(f: &mut File) {
    mp4parse::read_box_header(f).and_then(|h| {
        match &(mp4parse::fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                mp4parse::read_ftyp(&mut content, &h).and_then(|ftyp| {
                    println!("{}", ftyp);
                    Some(ftyp)
                })
            },
            _ => {
                println!("{}", h);
                mp4parse::skip_box_content(f, &h);
                None
            },
        }
    });
}

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            read_box(&mut f);
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(proc_macro)]

extern crate gtk;
#[macro_use]
extern crate mg;
extern crate mg_settings;
#[macro_use]
extern crate mg_settings_macros;

use gtk::{ContainerExt, Entry, Label, WidgetExt};
use gtk::Orientation::Vertical;
use mg::ApplicationBuilder;

use AppCommand::*;
use AppSettingsVariant::*;
use SpecialCommand::*;

#[derive(Debug, Setting)]
pub enum CustomSetting {
    #[default]
    Choice,
    OtherChoice,
}

#[derive(Commands)]
enum AppCommand {
    #[completion(hidden)]
    Follow,
    Insert,
    Normal,
    #[help(text="Open the url")]
    Open(String),
    #[help(text="Quit the application")]
    Quit,
    #[help(text="Open the url in a new window")]
    WinOpen(String),
}

#[derive(Default, Settings)]
pub struct AppSettings {
    boolean: bool,
    custom_set: CustomSetting,
    #[help(text="The window title")]
    title: String,
    title_len: i64,
    width: i64,
}

special_commands!(SpecialCommand {
    BackwardSearch('?', always),
    Search('/', always),
});

struct App {
    app: Box<mg::Application<AppCommand, AppSettings, SpecialCommand>>,
    label: Label,
}

impl App {
    fn new() -> Box<Self> {
        let mut app = ApplicationBuilder::new()
            .modes(hash! {
                "i" => "insert",
            })
            .settings(AppSettings::default())
            .build();

        app.use_dark_theme();

        let item = app.add_statusbar_item();
        item.set_text("Item");
        let item2 = app.add_statusbar_item();
        item2.set_text("Test");
        item.set_text("Rightmost");
        if let Err(error) = app.parse_config("examples/main.conf") {
            app.error(&error.to_string());
        }
        app.add_variable("url", || "http://duckduckgo.com/lite".to_string());
        app.set_window_title("First Mg Program");

        let vbox = gtk::Box::new(Vertical, 0);
        let label = Label::new(Some("Mg App"));
        vbox.add(&label);
        let entry = Entry::new();
        vbox.add(&entry);
        app.set_view(&vbox);

        entry.grab_focus();

        let mut app = Box::new(App {
            app: app,
            label: label,
        });

        connect!(app.app, connect_setting_changed(setting), app, setting_changed(setting));
        connect!(app.app, connect_command(command), app, handle_command(command));
        connect!(app.app, connect_mode_changed(mode), app, mode_changed(mode));
        connect!(app.app, connect_special_command(command), app, handle_special_command(command));

        app
    }

    fn handle_command(&mut self, command: AppCommand) {
        match command {
            Follow => (),
            Insert => self.app.set_mode("insert"),
            Normal => self.app.set_mode("normal"),
            Open(url) => self.label.set_text(&format!("Opening URL {}", url)),
            WinOpen(url) => self.label.set_text(&format!("Opening URL {} in new window", url)),
            Quit => gtk::main_quit(),
        }
    }

    fn handle_special_command(&self, command: SpecialCommand) {
        match command {
            BackwardSearch(input) => println!("Searching backward for {}", input),
            Search(input) => println!("Searching for {}", input),
        }
    }

    fn mode_changed(&mut self, mode: &str) {
        if mode != "normal" {
            {
                let title = &self.app.settings().title;
                self.label.set_text(&format!("Title was: {}", title));
            }
            self.app.set_setting(Title(mode.to_string()));
        }
    }

    fn setting_changed(&self, setting: &AppSettingsVariant) {
        match *setting {
            CustomSet(ref setting) => self.label.set_text(&format!("custom setting is: {:?}", setting)),
            Title(ref title) => self.app.set_window_title(&title),
            TitleLen(ref len) => self.app.set_window_title(&format!("New title len: {}", len)),
            Boolean(_) | Width(_) => (),
        }
    }
}

fn main() {
    gtk::init().unwrap();

    let _app = App::new();

    gtk::main();
}
<commit_msg>Fixed warnings.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(proc_macro)]

extern crate gtk;
#[macro_use]
extern crate mg;
extern crate mg_settings;
#[macro_use]
extern crate mg_settings_macros;

use gtk::{ContainerExt, Entry, Label, WidgetExt};
use gtk::Orientation::Vertical;
use mg::ApplicationBuilder;

use AppCommand::*;
use AppSettingsVariant::*;
use SpecialCommand::*;

#[derive(Debug, Setting)]
pub enum CustomSetting {
    #[default]
    Choice,
    OtherChoice,
}

#[derive(Commands)]
enum AppCommand {
    #[completion(hidden)]
    Follow,
    Insert,
    Normal,
    #[help(text="Open the url")]
    Open(String),
    #[help(text="Quit the application")]
    Quit,
    #[help(text="Open the url in a new window")]
    WinOpen(String),
}

#[derive(Default, Settings)]
pub struct AppSettings {
    boolean: bool,
    custom_set: CustomSetting,
    #[help(text="The window title")]
    title: String,
    title_len: i64,
    width: i64,
}

special_commands!(SpecialCommand {
    BackwardSearch('?', always),
    Search('/', always),
});

struct App {
    app: Box<mg::Application<AppCommand, AppSettings, SpecialCommand>>,
    label: Label,
}

impl App {
    fn new() -> Box<Self> {
        let mut app = ApplicationBuilder::new()
            .modes(hash! {
                "i" => "insert",
            })
            .settings(AppSettings::default())
            .build();

        app.use_dark_theme();

        let item = app.add_statusbar_item();
        item.set_text("Item");
        let item2 = app.add_statusbar_item();
        item2.set_text("Test");
        item.set_text("Rightmost");
        if let Err(error) = app.parse_config("examples/main.conf") {
            app.error(&error.to_string());
        }
        app.add_variable("url", || "http://duckduckgo.com/lite".to_string());
        app.set_window_title("First Mg Program");

        let vbox = gtk::Box::new(Vertical, 0);
        let label = Label::new(Some("Mg App"));
        vbox.add(&label);
        let entry = Entry::new();
        vbox.add(&entry);
        app.set_view(&vbox);

        entry.grab_focus();

        let mut app = Box::new(App {
            app: app,
            label: label,
        });

        connect!(app.app, connect_setting_changed(setting), app, setting_changed(setting));
        connect!(app.app, connect_command(command), app, handle_command(command));
        connect!(app.app, connect_mode_changed(mode), app, mode_changed(mode));
        connect!(app.app, connect_special_command(command), app, handle_special_command(command));

        app
    }

    fn handle_command(&mut self, command: AppCommand) {
        match command {
            Follow => (),
            Insert => self.app.set_mode("insert"),
            Normal => self.app.set_mode("normal"),
            Open(url) => self.label.set_text(&format!("Opening URL {}", url)),
            WinOpen(url) => self.label.set_text(&format!("Opening URL {} in new window", url)),
            Quit => gtk::main_quit(),
        }
    }

    fn handle_special_command(&self, command: SpecialCommand) {
        match command {
            BackwardSearch(input) => println!("Searching backward for {}", input),
            Search(input) => println!("Searching for {}", input),
        }
    }

    fn mode_changed(&mut self, mode: &str) {
        if mode != "normal" {
            {
                let title = &self.app.settings().title;
                self.label.set_text(&format!("Title was: {}", title));
            }
            self.app.set_setting(Title(mode.to_string()));
        }
    }

    fn setting_changed(&self, setting: &AppSettingsVariant) {
        match *setting {
            CustomSet(ref setting) => self.label.set_text(&format!("custom setting is: {:?}", setting)),
            Title(ref title) => self.app.set_window_title(title),
            TitleLen(ref len) => self.app.set_window_title(&format!("New title len: {}", len)),
            Boolean(_) | Width(_) => (),
        }
    }
}

fn main() {
    gtk::init().unwrap();

    let _app = App::new();

    gtk::main();
}
<|endoftext|>