<commit_before>//
//
//

use memory::virt::ProtectionMode;
use arch::memory::PAddr;

const KERNEL_BASE_TABLE: usize = 0xFFFF8000;

pub fn is_fixed_alloc<T>(_addr: *const T, _size: usize) -> bool {
	//const BASE : usize = super::addresses::KERNEL_BASE;
	//const ONEMEG: usize =1024*1024
	//const LIMIT: usize = super::addresses::KERNEL_BASE + 4*ONEMEG;
	false
}
// UNSAFE: Can cause aliasing
pub unsafe fn fixed_alloc(_p: PAddr, _count: usize) -> Option<*mut ()> {
	None
}

#[derive(Copy,Clone)]
enum PageEntryRegion {
	NonGlobal,
	Global,
}
impl PageEntryRegion {
	unsafe fn get_section_ent(&self, idx: usize) -> &mut u32 {
		assert!(idx < 4096);
		match self
		{
		&PageEntryRegion::NonGlobal => todo!("PageEntryRegion::get_section_ent - non-global"),
		&PageEntryRegion::Global => &mut *((KERNEL_BASE_TABLE + idx * 4) as *mut u32),
		}
	}
}
enum PageEntry {
	Section {
		rgn: PageEntryRegion,
		idx: usize,
		ofs: usize
		},
	Page {
		mapping: TempHandle,
		idx: usize,
		ofs: usize
		},
}
impl PageEntry
{
	fn alloc(addr: *const (), level: usize) -> Result<PageEntry, ()> {
		todo!("PageEntry::alloc({:p}, level={})", addr, level);
	}
	/// Obtain a page entry for the specified address
	fn get(addr: *const ()) -> PageEntry {
		use super::addresses::KERNEL_BASE;
		let (rgn, p_idx) = if (addr as usize) < KERNEL_BASE {
				(PageEntryRegion::NonGlobal, (addr as usize - KERNEL_BASE) >> 12)
			}
			else {
				(PageEntryRegion::Global, (addr as usize) >> 12)
			};

		// SAFE: Aliasing in this case is benign
		let sect_ent = unsafe { *rgn.get_section_ent(p_idx >> 8) };
		if sect_ent & 0b11 == 0b01 {
			PageEntry::Page {
				// SAFE: ... won't be mutated (yet), but need to ensure safety TODO
				mapping: unsafe { TempHandle::new( sect_ent & !0xFFF ) },
				idx: p_idx,
				ofs: (addr as usize) & 0xFFF,
				}
		}
		else {
			PageEntry::Section {
				rgn: rgn,
				idx: p_idx >> 8,
				ofs: (addr as usize) & 0xFF_FFF,
				}
		}
	}

	fn is_reserved(&self) -> bool {
		// TODO: Need to _ensure_ that the page table is not removed during manipulation
		// SAFE: Aliasing is benign, and page table should be mapped (see above TODO)
		unsafe {
			match self
			{
			&PageEntry::Section { rgn, idx, .. } => (*rgn.get_section_ent(idx) & 3 != 0),
			&PageEntry::Page { ref mapping, idx, .. } => (mapping[idx & 0x3FF] & 3 != 0),
			}
		}
	}

	fn phys_addr(&self) -> ::arch::memory::PAddr {
		// SAFE: Aliasing is benign, and page table should be mapped (see above TODO)
		unsafe {
			match self
			{
			&PageEntry::Section { rgn, idx, ofs } => (*rgn.get_section_ent(idx) & !0xFFF) + ofs as u32,
			&PageEntry::Page { ref mapping, idx ,ofs } => (mapping[idx & 0x3FF] & !0xFFF) + ofs as u32,
			}
		}
	}
}

#[repr(C)]
struct AtomicU32(::core::cell::UnsafeCell<u32>);
impl AtomicU32 {
	pub fn cxchg(&self, val: u32, new: u32) -> u32 {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_cxchg_relaxed(self.0.get(), val, new) }
	}
	pub fn store(&self, val: u32) {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_store_relaxed(self.0.get(), val) }
	}
	pub fn load(&self) -> u32 {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_load_relaxed(self.0.get()) }
	}
}
extern "C" {
	static kernel_table0: [AtomicU32; 0x800*2];
	static kernel_exception_map: [AtomicU32; 1024];
}

fn get_table_addr<T>(a: *const T, alloc: bool) -> Option< (::arch::memory::PAddr, usize) > {
	let addr = a as usize;
	let page = addr >> 12;
	let (ttbr_ofs, tab_idx) = (page >> 8, page & 0xFF);
	let ent_r = if ttbr_ofs < 0x800 {
			todo!("get_table_addr - User");
		}
		else {
			// Kernel
			&kernel_table0[ ttbr_ofs ]
		};

	//let ent_v = ent_r.load();
	let ent_v = ent_r.load();
	match ent_v & 0xFFF
	{
	0 => if alloc {
			let frame = ::memory::phys::allocate_bare().expect("TODO get_table_addr");
			let ent_v = ent_r.cxchg(0, frame + 0x1);
			if ent_v != 0 {
				::memory::phys::deref_frame(frame);
				Some( (ent_v & !0xFFF, tab_idx) )
			}
			else {
				Some( (frame & !0xFFF, tab_idx) )
			}
		}
		else {
			None
		},
	1 => Some( (ent_v & !0xFFF, tab_idx) ),
	v @ _ => todo!("get_table_addr - Other flags bits {:#x}", v),
	}
}
//static S_TEMP_MAP_SEMAPHORE: Semaphore = Semaphore::new();
const KERNEL_TEMP_BASE : usize = 0xFFC00000;

struct TempHandle(*mut [u32; 1024]);
impl TempHandle
{
	/// UNSAFE: User must ensure that address is valid, and that no aliasing occurs
	unsafe fn new(phys: ::arch::memory::PAddr) -> TempHandle {
		let val = (phys as u32) + 0x13;

		//S_TEMP_MAP_SEMAPHORE.take();
		// #1023 is reserved for -1 mapping
		for i in 0 .. 1023 {
			if kernel_exception_map[i].cxchg(0, val) == 0 {
				return TempHandle( (KERNEL_TEMP_BASE + i * 0x1000) as *mut _ );
			}
		}
		panic!("No free temp mappings");
	}
}
impl ::core::ops::Deref for TempHandle {
	type Target = [u32];
	fn deref(&self) -> &[u32] {
		// SAFE: We should have unique access
		unsafe { &*self.0 }
	}
}
impl ::core::ops::DerefMut for TempHandle {
	fn deref_mut(&mut self) -> &mut [u32] {
		// SAFE: We should have unique access
		unsafe { &mut *self.0 }
	}
}
impl ::core::ops::Drop for TempHandle {
	fn drop(&mut self) {
		let i = (self.0 as usize - KERNEL_TEMP_BASE) / 0x1000;
		kernel_exception_map[i].store(0);
		//S_TEMP_MAP_SEMAPHORE.add();
	}
}

pub fn is_reserved<T>(addr: *const T) -> bool {
	PageEntry::get(addr as *const ()).is_reserved()
}
pub fn get_phys<T>(addr: *const T) -> ::arch::memory::PAddr {
	PageEntry::get(addr as *const ()).phys_addr()
}

pub fn get_info<T>(addr: *const T) -> Option<(u32, ::memory::virt::ProtectionMode)> {
	todo!("get_info")
}

pub unsafe fn map(a: *mut (), p: PAddr, mode: ProtectionMode) {
	// 1. Map the relevant table in the temp area
	let (tab_phys, idx) = get_table_addr(a, true).unwrap();
	// TODO: Ensure nothing else is manipulating this segment of AS
	let mut mh = TempHandle::new( tab_phys );
	// 2. Insert
	let mode_flags = match mode
		{
		ProtectionMode::Unmapped => panic!("Invalid pass of Unmapped to map"),
		ProtectionMode::KernelRO => 0x212,
		ProtectionMode::KernelRW => 0x012,
		ProtectionMode::KernelRX => 0x053,
		ProtectionMode::UserRO => 0x232,
		ProtectionMode::UserRW => 0x032,
		ProtectionMode::UserRX => 0x233,
		ProtectionMode::UserRWX => 0x033,
		ProtectionMode::UserCOW => 0x223,	// 1,10 is a deprecated encoding for RO, need to find a better encoding
		};
	mh[idx] = p + mode_flags;
}
pub unsafe fn reprotect(a: *mut (), mode: ProtectionMode) {
	todo!("reprotect({:p}, {:?}", a, mode)
}
pub unsafe fn unmap(a: *mut ()) -> Option<PAddr> {
	todo!("unmap")
}

#[derive(Debug)]
pub struct AddressSpace(u32);
impl AddressSpace
{
	pub fn pid0() -> AddressSpace {
		extern "C" {
			static kernel_table0_ofs: ::Void;
			static kernel_data_start: u32;
		}
		let tab0_addr = kernel_data_start + (&kernel_table0_ofs as *const _ as usize as u32);
		AddressSpace( tab0_addr )
	}
	pub fn new(clone_start: usize, clone_end: usize) -> Result<AddressSpace,::memory::virt::MapError> {
		todo!("AddressSpace::new({:#x} -- {:#x})", clone_start, clone_end);
	}

	pub fn get_ttbr0(&self) -> u32 { self.0 }
}

<commit_msg>Kernel/ARMv7 - Further cleanup<commit_after>//
//
//

use memory::virt::ProtectionMode;
use arch::memory::PAddr;

const KERNEL_BASE_TABLE: usize = 0xFFFF8000;

#[repr(C)]
/// Atomic 32-bit integer, used for table entries
struct AtomicU32(::core::cell::UnsafeCell<u32>);
impl AtomicU32 {
	/// Compare and exchange, returns old value and writes `new` if it was equal to `val`
	pub fn cxchg(&self, val: u32, new: u32) -> u32 {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_cxchg_relaxed(self.0.get(), val, new) }
	}
	/// Unconditionally stores
	pub fn store(&self, val: u32) {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_store_relaxed(self.0.get(), val) }
	}
	/// Unconditionally loads
	pub fn load(&self) -> u32 {
		// SAFE: Atomic
		unsafe { ::core::intrinsics::atomic_load_relaxed(self.0.get()) }
	}
}

pub fn is_fixed_alloc<T>(_addr: *const T, _size: usize) -> bool {
	//const BASE : usize = super::addresses::KERNEL_BASE;
	//const ONEMEG: usize = 1024*1024
	//const LIMIT: usize = super::addresses::KERNEL_BASE + 4*ONEMEG;
	false
}
// UNSAFE: Can cause aliasing
pub unsafe fn fixed_alloc(_p: PAddr, _count: usize) -> Option<*mut ()> {
	None
}

#[derive(Copy,Clone,Debug)]
enum PageEntryRegion {
	NonGlobal,
	Global,
}
impl PageEntryRegion {
	unsafe fn get_section_ent(&self, idx: usize) -> &mut u32 {
		assert!(idx < 4096);
		match self
		{
		&PageEntryRegion::NonGlobal => todo!("PageEntryRegion::get_section_ent - non-global"),
		&PageEntryRegion::Global => &mut *((KERNEL_BASE_TABLE + idx * 4) as *mut u32),
		}
	}
}
enum PageEntry {
	Section {
		rgn: PageEntryRegion,
		idx: usize,
		ofs: usize
		},
	Page {
		mapping: TempHandle,
		idx: usize,
		ofs: usize
		},
}
impl PageEntry
{
	fn alloc(addr: *const (), level: usize) -> Result<PageEntry, ()> {
		todo!("PageEntry::alloc({:p}, level={})", addr, level);
	}
	/// Obtain a page entry for the specified address
	fn get(addr: *const ()) -> PageEntry {
		use super::addresses::KERNEL_BASE;
		let (rgn, p_idx) = if (addr as usize) < KERNEL_BASE {
				(PageEntryRegion::NonGlobal, (addr as usize - KERNEL_BASE) >> 12)
			}
			else {
				(PageEntryRegion::Global, (addr as usize) >> 12)
			};

		// SAFE: Aliasing in this case is benign
		let sect_ent = unsafe { *rgn.get_section_ent(p_idx >> 8) };
		if sect_ent & 0b11 == 0b01 {
			PageEntry::Page {
				// SAFE: ... won't be mutated (yet), but need to ensure safety TODO
				mapping: unsafe { TempHandle::new( sect_ent & !0xFFF ) },
				idx: p_idx,
				ofs: (addr as usize) & 0xFFF,
				}
		}
		else {
			PageEntry::Section {
				rgn: rgn,
				idx: p_idx >> 8,
				ofs: (addr as usize) & 0xFF_FFF,
				}
		}
	}

	fn is_reserved(&self) -> bool {
		// TODO: Need to _ensure_ that the page table is not removed during manipulation
		// SAFE: Aliasing is benign, and page table should be mapped (see above TODO)
		unsafe {
			match self
			{
			&PageEntry::Section { rgn, idx, .. } => (*rgn.get_section_ent(idx) & 3 != 0),
			&PageEntry::Page { ref mapping, idx, .. } => (mapping[idx & 0x3FF] & 3 != 0),
			}
		}
	}

	fn phys_addr(&self) -> ::arch::memory::PAddr {
		// SAFE: Aliasing is benign, and page table should be mapped (see above TODO)
		unsafe {
			match self
			{
			&PageEntry::Section { rgn, idx, ofs } => (*rgn.get_section_ent(idx) & !0xFFF) + ofs as u32,
			&PageEntry::Page { ref mapping, idx ,ofs } => (mapping[idx & 0x3FF] & !0xFFF) + ofs as u32,
			}
		}
	}
	fn mode(&self) -> ::memory::virt::ProtectionMode {
		// SAFE: Aliasing is benign, and page table should be mapped (see above TODO)
		unsafe {
			match self
			{
			&PageEntry::Section { rgn, idx, .. } =>
				match *rgn.get_section_ent(idx) & 0xFFF
				{
				0x000 => ProtectionMode::Unmapped,
				0x402 => ProtectionMode::KernelRW,
				v @ _ => todo!("Unknown mode value in section {:?} {} - {:#x}", rgn, idx, v),
				},
			&PageEntry::Page { ref mapping, idx, ofs } =>
				match mapping[idx & 0x3FF] & 0xFFF
				{
				0x000 => ProtectionMode::Unmapped,
				0x212 => ProtectionMode::KernelRO,
				0x012 => ProtectionMode::KernelRW,
				0x053 => ProtectionMode::KernelRX,
				0x232 => ProtectionMode::UserRO,
				0x032 => ProtectionMode::UserRW,
				0x233 => ProtectionMode::UserRX,
				0x033 => ProtectionMode::UserRWX,
				0x223 => ProtectionMode::UserCOW,
				v @ _ => todo!("Unknown mode value in page {} - {:#x}", idx, v),
				},
			}
		}
	}
}

extern "C" {
	static kernel_table0: [AtomicU32; 0x800*2];
	static kernel_exception_map: [AtomicU32; 1024];
}

/// Returns the physical address of the table controlling `vaddr`. If `alloc` is true, a new table will be allocated if needed.
fn get_table_addr<T>(vaddr: *const T, alloc: bool) -> Option< (::arch::memory::PAddr, usize) > {
	let addr = vaddr as usize;
	let page = addr >> 12;
	let (ttbr_ofs, tab_idx) = (page >> 8, page & 0xFF);
	let ent_r = if ttbr_ofs < 0x800 {
			todo!("get_table_addr - User");
		}
		else {
			// Kernel
			&kernel_table0[ ttbr_ofs ]
		};

	//let ent_v = ent_r.load();
	let ent_v = ent_r.load();
	match ent_v & 0xFFF
	{
	0 => if alloc {
			let frame = ::memory::phys::allocate_bare().expect("TODO get_table_addr");
			let ent_v = ent_r.cxchg(0, frame + 0x1);
			if ent_v != 0 {
				::memory::phys::deref_frame(frame);
				Some( (ent_v & !0xFFF, tab_idx) )
			}
			else {
				Some( (frame & !0xFFF, tab_idx) )
			}
		}
		else {
			None
		},
	1 => Some( (ent_v & !0xFFF, tab_idx) ),
	v @ _ => todo!("get_table_addr - Other flags bits {:#x}", v),
	}
}

//static S_TEMP_MAP_SEMAPHORE: Semaphore = Semaphore::new();
const KERNEL_TEMP_BASE : usize = 0xFFC00000;

/// Handle to a temporarily mapped frame
struct TempHandle(*mut [u32; 1024]);
impl TempHandle
{
	/// UNSAFE: User must ensure that address is valid, and that no aliasing occurs
	unsafe fn new(phys: ::arch::memory::PAddr) -> TempHandle {
		let val = (phys as u32) + 0x13;

		//S_TEMP_MAP_SEMAPHORE.take();
		// #1023 is reserved for -1 mapping
		for i in 0 .. 1023 {
			if kernel_exception_map[i].cxchg(0, val) == 0 {
				return TempHandle( (KERNEL_TEMP_BASE + i * 0x1000) as *mut _ );
			}
		}
		panic!("No free temp mappings");
	}
}
impl ::core::ops::Deref for TempHandle {
	type Target = [u32];
	fn deref(&self) -> &[u32] {
		// SAFE: We should have unique access
		unsafe { &*self.0 }
	}
}
impl ::core::ops::DerefMut for TempHandle {
	fn deref_mut(&mut self) -> &mut [u32] {
		// SAFE: We should have unique access
		unsafe { &mut *self.0 }
	}
}
impl ::core::ops::Drop for TempHandle {
	fn drop(&mut self) {
		let i = (self.0 as usize - KERNEL_TEMP_BASE) / 0x1000;
		kernel_exception_map[i].store(0);
		//S_TEMP_MAP_SEMAPHORE.add();
	}
}

pub fn is_reserved<T>(addr: *const T) -> bool {
	PageEntry::get(addr as *const ()).is_reserved()
}
pub fn get_phys<T>(addr: *const T) -> ::arch::memory::PAddr {
	PageEntry::get(addr as *const ()).phys_addr()
}

pub fn get_info<T>(addr: *const T) -> Option<(u32, ::memory::virt::ProtectionMode)> {
	todo!("get_info")
}

pub unsafe fn map(a: *mut (), p: PAddr, mode: ProtectionMode) {
	// 1. Map the relevant table in the temp area
	let (tab_phys, idx) = get_table_addr(a, true).unwrap();
	// TODO: Ensure nothing else is manipulating this segment of AS. (Otherwise we'll see aliasing in TempHandle)
	let mut mh = TempHandle::new( tab_phys );
	// 2. Insert
	let mode_flags = match mode
		{
		ProtectionMode::Unmapped => panic!("Invalid pass of Unmapped to map"),
		ProtectionMode::KernelRO => 0x212,
		ProtectionMode::KernelRW => 0x012,
		ProtectionMode::KernelRX => 0x053,
		ProtectionMode::UserRO => 0x232,
		ProtectionMode::UserRW => 0x032,
		ProtectionMode::UserRX => 0x233,
		ProtectionMode::UserRWX => 0x033,
		ProtectionMode::UserCOW => 0x223,	// 1,10 is a deprecated encoding for RO, need to find a better encoding
		};
	mh[idx] = p + mode_flags;
}
pub unsafe fn reprotect(a: *mut (), mode: ProtectionMode) {
	todo!("reprotect({:p}, {:?}", a, mode)
}
pub unsafe fn unmap(a: *mut ()) -> Option<PAddr> {
	todo!("unmap")
}

#[derive(Debug)]
pub struct AddressSpace(u32);
impl AddressSpace
{
	pub fn pid0() -> AddressSpace {
		extern "C" {
			static kernel_table0_ofs: ::Void;
			static kernel_data_start: u32;
		}
		let tab0_addr = kernel_data_start + (&kernel_table0_ofs as *const _ as usize as u32);
		AddressSpace( tab0_addr )
	}
	pub fn new(clone_start: usize, clone_end: usize) -> Result<AddressSpace,::memory::virt::MapError> {
		todo!("AddressSpace::new({:#x} -- {:#x})", clone_start, clone_end);
	}

	pub fn get_ttbr0(&self) -> u32 { self.0 }
}

<|endoftext|>


<commit_before>// This module implements useful format related utilities.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std;

/// This helps with formatting text-based help pages.
pub struct HelpFormatter {
    width: isize,
    indent_increment: isize,
    current_indent: isize,
}

impl HelpFormatter {
    /// Create one new help formatter.
    ///
    /// - `indent_increment` - the additional increment for each level.
    /// - `width` - the width for the text.
    ///
    pub fn new(width: isize, indent_increment: isize) -> HelpFormatter {
        HelpFormatter {
            width: width,
            indent_increment: indent_increment,
            current_indent: 0,
        }
    }
}
<commit_msg>Added wrap_text<commit_after>// This module implements useful format related utilities.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std;
use std::cmp::max;

/// This helps with formatting text-based help pages.
pub struct HelpFormatter {
    width: usize,
    indent_increment: usize,
    current_indent: usize,
    buffer: Vec<String>,
}

impl HelpFormatter {
    /// Create one new help formatter.
    ///
    /// - `indent_increment` - the additional increment for each level.
    /// - `width` - the width for the text.
    ///
    pub fn new(width: usize, indent_increment: usize) -> HelpFormatter {
        HelpFormatter {
            width: width,
            indent_increment: indent_increment,
            current_indent: 0,
            buffer: Vec::new(),
        }
    }

    /// Increases the indentation.
    fn indent(&mut self) {
        self.current_indent = self.current_indent + self.indent_increment;
    }

    /// Decreases the indentation.
    fn dedent(&mut self) {
        self.current_indent = self.current_indent - self.indent_increment;
    }

    /// Writes a string into the internal buffer.
    pub fn write(&mut self, s: String) {
        self.buffer.push(s);
    }

    /// Writes a usage line.
    pub fn write_usage(&mut self, name: &str, args: String, prefix: &str) {
        let prefix = format!("{:>2$}{}", prefix, name, self.current_indent);
        let prefix_len = prefix.len();
        self.write(prefix);
        let text_width = max(self.width - self.current_indent - prefix_len, 10);
        let mut indent = String::from_str(" ");
        for _ in range(0, prefix_len) {
            indent.push_str(" ");
        }
        self.write(wrap_text(args, text_width, " ", indent.as_slice()));
        self.write(String::from_str("\n"));
    }
}

/// A helper function that wraps text.
/// TODO
fn wrap_text(text: String, width: usize, initial_indent: &str, subsequent_indent: &str) -> String {
    return text;
}
<|endoftext|>


<commit_before>//! AArch64 intrinsics.
//!
//! The reference for NEON is [ARM's NEON Intrinsics Reference][arm_ref]. The
//! [ARM's NEON Intrinsics Online Database][arm_dat] is also useful.
//!
//! [arm_ref]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
//! [arm_dat]: https://developer.arm.com/technologies/neon/intrinsics

mod v8;
pub use self::v8::*;

mod neon;
pub use self::neon::*;

mod crypto;
pub use self::crypto::*;

#[cfg(not(bootstrap))]
mod tme;
#[cfg(not(bootstrap))]
pub use self::tme::*;

mod crc;
pub use self::crc::*;

pub use super::acle::*;

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

/// Generates the trap instruction `BRK 1`
#[cfg_attr(test, assert_instr(brk))]
#[inline]
pub unsafe fn brk() -> ! {
    crate::intrinsics::abort()
}

#[cfg(test)]
pub(crate) mod test_support;
<commit_msg>Remove cfg(not(bootstrap)) (#885)<commit_after>//! AArch64 intrinsics.
//!
//! The reference for NEON is [ARM's NEON Intrinsics Reference][arm_ref]. The
//! [ARM's NEON Intrinsics Online Database][arm_dat] is also useful.
//!
//! [arm_ref]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
//! [arm_dat]: https://developer.arm.com/technologies/neon/intrinsics

mod v8;
pub use self::v8::*;

mod neon;
pub use self::neon::*;

mod crypto;
pub use self::crypto::*;

mod tme;
pub use self::tme::*;

mod crc;
pub use self::crc::*;

pub use super::acle::*;

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

/// Generates the trap instruction `BRK 1`
#[cfg_attr(test, assert_instr(brk))]
#[inline]
pub unsafe fn brk() -> ! {
    crate::intrinsics::abort()
}

#[cfg(test)]
pub(crate) mod test_support;
<|endoftext|>


<commit_before>//! Entry point for call-hierarchy

use indexmap::IndexMap;

use hir::db::AstDatabase;
use ra_syntax::{
    ast::{self, DocCommentsOwner},
    match_ast, AstNode, TextRange,
};

use crate::{
    call_info::FnCallNode,
    db::RootDatabase,
    display::{ShortLabel, ToNav},
    expand::descend_into_macros,
    goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
};

#[derive(Default)]
struct CallLocations {
    funcs: IndexMap<NavigationTarget, Vec<TextRange>>,
}

impl CallLocations {
    pub fn add(&mut self, target: &NavigationTarget, range: TextRange) {
        self.funcs.entry(target.clone()).or_default().push(range);
    }

    pub fn into_items(self) -> Vec<CallItem> {
        self.funcs.into_iter().map(|(target, ranges)| CallItem { target, ranges }).collect()
    }
}

#[derive(Debug, Clone)]
pub struct CallItem {
    pub target: NavigationTarget,
    pub ranges: Vec<TextRange>,
}

impl CallItem {
    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        format!("{} : {:?}", self.target.debug_render(), self.ranges)
    }
}

pub(crate) fn call_hierarchy(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    goto_definition::goto_definition(db, position)
}

pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    // 1. Find all refs
    // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
    // 3. Add ranges relative to the start of the fndef.
    let refs = references::find_all_refs(db, position, None)?;

    let mut calls = CallLocations::default();

    for reference in refs.info.references() {
        let file_id = reference.file_range.file_id;
        let file = db.parse_or_expand(file_id.into())?;
        let token = file.token_at_offset(reference.file_range.range.start()).next()?;
        let token = descend_into_macros(db, file_id, token);
        let syntax = token.value.parent();

        // This target is the containing function
        if let Some(nav) = syntax.ancestors().find_map(|node| {
            match_ast! {
                match node {
                    ast::FnDef(it) => {
                        Some(NavigationTarget::from_named(
                            db,
                            token.with_value(&it),
                            it.doc_comment_text(),
                            it.short_label(),
                        ))
                    },
                    _ => { None },
                }
            }
        }) {
            let relative_range = reference.file_range.range;
            calls.add(&nav, relative_range);
        }
    }

    Some(calls.into_items())
}

pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let file_id = position.file_id;
    let file = db.parse_or_expand(file_id.into())?;
    let token = file.token_at_offset(position.offset).next()?;
    let token = descend_into_macros(db, file_id, token);
    let syntax = token.value.parent();

    let mut calls = CallLocations::default();

    syntax
        .descendants()
        .filter_map(|node| FnCallNode::with_node_exact(&node))
        .filter_map(|call_node| {
            let name_ref = call_node.name_ref()?;
            let name_ref = token.with_value(name_ref.syntax());

            let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);

            if let Some(func_target) = match &call_node {
                FnCallNode::CallExpr(expr) => {
                    //FIXME: Type::as_callable is broken
                    let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
                    match callable_def {
                        hir::CallableDef::FunctionId(it) => {
                            let fn_def: hir::Function = it.into();
                            let nav = fn_def.to_nav(db);
                            Some(nav)
                        }
                        _ => None,
                    }
                }
                FnCallNode::MethodCallExpr(expr) => {
                    let function = analyzer.resolve_method_call(&expr)?;
                    Some(function.to_nav(db))
                }
                FnCallNode::MacroCallExpr(expr) => {
                    let macro_def = analyzer.resolve_macro_call(db, name_ref.with_value(&expr))?;
                    Some(macro_def.to_nav(db))
                }
            } {
                Some((func_target.clone(), name_ref.value.text_range()))
            } else {
                None
            }
        })
        .for_each(|(nav, range)| calls.add(&nav, range));

    Some(calls.into_items())
}

#[cfg(test)]
mod tests {
    use ra_db::FilePosition;

    use crate::mock_analysis::analysis_and_position;

    fn check_hierarchy(
        fixture: &str,
        expected: &str,
        expected_incoming: &[&str],
        expected_outgoing: &[&str],
    ) {
        let (analysis, pos) = analysis_and_position(fixture);

        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), 1);
        let nav = navs.pop().unwrap();
        nav.assert_match(expected);

        let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() };
        let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
        assert_eq!(incoming_calls.len(), expected_incoming.len());

        for call in 0..incoming_calls.len() {
            incoming_calls[call].assert_match(expected_incoming[call]);
        }

        let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
        assert_eq!(outgoing_calls.len(), expected_outgoing.len());

        for call in 0..outgoing_calls.len() {
            outgoing_calls[call].assert_match(expected_outgoing[call]);
        }
    }

    #[test]
    fn test_call_hierarchy_on_ref() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller() {
                call<|>ee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 44) [18; 24) : [[33; 39)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_on_def() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn call<|>ee() {}
            fn caller() {
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 44) [18; 24) : [[33; 39)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_same_fn() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller() {
                call<|>ee();
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 58) [18; 24) : [[33; 39), [47; 53)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_fn() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller1() {
                call<|>ee();
            }

            fn caller2() {
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &[
                "caller1 FN_DEF FileId(1) [15; 45) [18; 25) : [[34; 40)]",
                "caller2 FN_DEF FileId(1) [46; 76) [49; 56) : [[65; 71)]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_files() {
        check_hierarchy(
            r#"
            //- /lib.rs
            mod foo;
            use foo::callee;

            fn caller() {
                call<|>ee();
            }

            //- /foo/mod.rs
            pub fn callee() {}
            "#,
            "callee FN_DEF FileId(2) [0; 18) [7; 13)",
            &["caller FN_DEF FileId(1) [26; 55) [29; 35) : [[44; 50)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn call<|>er() {
                callee();
                callee();
            }
            "#,
            "caller FN_DEF FileId(1) [15; 58) [18; 24)",
            &[],
            &["callee FN_DEF FileId(1) [0; 14) [3; 9) : [[33; 39), [47; 53)]"],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing_in_different_files() {
        check_hierarchy(
            r#"
            //- /lib.rs
            mod foo;
            use foo::callee;

            fn call<|>er() {
                callee();
            }

            //- /foo/mod.rs
            pub fn callee() {}
            "#,
            "caller FN_DEF FileId(1) [26; 55) [29; 35)",
            &[],
            &["callee FN_DEF FileId(2) [0; 18) [7; 13) : [[44; 50)]"],
        );
    }

    #[test]
    fn test_call_hierarchy_incoming_outgoing() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn caller1() {
                call<|>er2();
            }

            fn caller2() {
                caller3();
            }

            fn caller3() {

            }
            "#,
            "caller2 FN_DEF FileId(1) [32; 63) [35; 42)",
            &["caller1 FN_DEF FileId(1) [0; 31) [3; 10) : [[19; 26)]"],
            &["caller3 FN_DEF FileId(1) [64; 80) [67; 74) : [[51; 58)]"],
        );
    }
}
<commit_msg>Move private API down<commit_after>//! Entry point for call-hierarchy

use indexmap::IndexMap;

use hir::db::AstDatabase;
use ra_syntax::{
    ast::{self, DocCommentsOwner},
    match_ast, AstNode, TextRange,
};

use crate::{
    call_info::FnCallNode,
    db::RootDatabase,
    display::{ShortLabel, ToNav},
    expand::descend_into_macros,
    goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
};

#[derive(Debug, Clone)]
pub struct CallItem {
    pub target: NavigationTarget,
    pub ranges: Vec<TextRange>,
}

impl CallItem {
    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        format!("{} : {:?}", self.target.debug_render(), self.ranges)
    }
}

pub(crate) fn call_hierarchy(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    goto_definition::goto_definition(db, position)
}

pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    // 1. Find all refs
    // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
    // 3. Add ranges relative to the start of the fndef.
    let refs = references::find_all_refs(db, position, None)?;

    let mut calls = CallLocations::default();

    for reference in refs.info.references() {
        let file_id = reference.file_range.file_id;
        let file = db.parse_or_expand(file_id.into())?;
        let token = file.token_at_offset(reference.file_range.range.start()).next()?;
        let token = descend_into_macros(db, file_id, token);
        let syntax = token.value.parent();

        // This target is the containing function
        if let Some(nav) = syntax.ancestors().find_map(|node| {
            match_ast! {
                match node {
                    ast::FnDef(it) => {
                        Some(NavigationTarget::from_named(
                            db,
                            token.with_value(&it),
                            it.doc_comment_text(),
                            it.short_label(),
                        ))
                    },
                    _ => { None },
                }
            }
        }) {
            let relative_range = reference.file_range.range;
            calls.add(&nav, relative_range);
        }
    }

    Some(calls.into_items())
}

pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let file_id = position.file_id;
    let file = db.parse_or_expand(file_id.into())?;
    let token = file.token_at_offset(position.offset).next()?;
    let token = descend_into_macros(db, file_id, token);
    let syntax = token.value.parent();

    let mut calls = CallLocations::default();

    syntax
        .descendants()
        .filter_map(|node| FnCallNode::with_node_exact(&node))
        .filter_map(|call_node| {
            let name_ref = call_node.name_ref()?;
            let name_ref = token.with_value(name_ref.syntax());

            let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);

            if let Some(func_target) = match &call_node {
                FnCallNode::CallExpr(expr) => {
                    //FIXME: Type::as_callable is broken
                    let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
                    match callable_def {
                        hir::CallableDef::FunctionId(it) => {
                            let fn_def: hir::Function = it.into();
                            let nav = fn_def.to_nav(db);
                            Some(nav)
                        }
                        _ => None,
                    }
                }
                FnCallNode::MethodCallExpr(expr) => {
                    let function = analyzer.resolve_method_call(&expr)?;
                    Some(function.to_nav(db))
                }
                FnCallNode::MacroCallExpr(expr) => {
                    let macro_def = analyzer.resolve_macro_call(db, name_ref.with_value(&expr))?;
                    Some(macro_def.to_nav(db))
                }
            } {
                Some((func_target.clone(), name_ref.value.text_range()))
            } else {
                None
            }
        })
        .for_each(|(nav, range)| calls.add(&nav, range));

    Some(calls.into_items())
}

#[derive(Default)]
struct CallLocations {
    funcs: IndexMap<NavigationTarget, Vec<TextRange>>,
}

impl CallLocations {
    fn add(&mut self, target: &NavigationTarget, range: TextRange) {
        self.funcs.entry(target.clone()).or_default().push(range);
    }

    fn into_items(self) -> Vec<CallItem> {
        self.funcs.into_iter().map(|(target, ranges)| CallItem { target, ranges }).collect()
    }
}

#[cfg(test)]
mod tests {
    use ra_db::FilePosition;

    use crate::mock_analysis::analysis_and_position;

    fn check_hierarchy(
        fixture: &str,
        expected: &str,
        expected_incoming: &[&str],
        expected_outgoing: &[&str],
    ) {
        let (analysis, pos) = analysis_and_position(fixture);

        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), 1);
        let nav = navs.pop().unwrap();
        nav.assert_match(expected);

        let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() };
        let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
        assert_eq!(incoming_calls.len(), expected_incoming.len());

        for call in 0..incoming_calls.len() {
            incoming_calls[call].assert_match(expected_incoming[call]);
        }

        let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
        assert_eq!(outgoing_calls.len(), expected_outgoing.len());

        for call in 0..outgoing_calls.len() {
            outgoing_calls[call].assert_match(expected_outgoing[call]);
        }
    }

    #[test]
    fn test_call_hierarchy_on_ref() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller() {
                call<|>ee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 44) [18; 24) : [[33; 39)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_on_def() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn call<|>ee() {}
            fn caller() {
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 44) [18; 24) : [[33; 39)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_same_fn() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller() {
                call<|>ee();
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &["caller FN_DEF FileId(1) [15; 58) [18; 24) : [[33; 39), [47; 53)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_fn() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn caller1() {
                call<|>ee();
            }

            fn caller2() {
                callee();
            }
            "#,
            "callee FN_DEF FileId(1) [0; 14) [3; 9)",
            &[
                "caller1 FN_DEF FileId(1) [15; 45) [18; 25) : [[34; 40)]",
                "caller2 FN_DEF FileId(1) [46; 76) [49; 56) : [[65; 71)]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_files() {
        check_hierarchy(
            r#"
            //- /lib.rs
            mod foo;
            use foo::callee;

            fn caller() {
                call<|>ee();
            }

            //- /foo/mod.rs
            pub fn callee() {}
            "#,
            "callee FN_DEF FileId(2) [0; 18) [7; 13)",
            &["caller FN_DEF FileId(1) [26; 55) [29; 35) : [[44; 50)]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn callee() {}
            fn call<|>er() {
                callee();
                callee();
            }
            "#,
            "caller FN_DEF FileId(1) [15; 58) [18; 24)",
            &[],
            &["callee FN_DEF FileId(1) [0; 14) [3; 9) : [[33; 39), [47; 53)]"],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing_in_different_files() {
        check_hierarchy(
            r#"
            //- /lib.rs
            mod foo;
            use foo::callee;

            fn call<|>er() {
                callee();
            }

            //- /foo/mod.rs
            pub fn callee() {}
            "#,
            "caller FN_DEF FileId(1) [26; 55) [29; 35)",
            &[],
            &["callee FN_DEF FileId(2) [0; 18) [7; 13) : [[44; 50)]"],
        );
    }

    #[test]
    fn test_call_hierarchy_incoming_outgoing() {
        check_hierarchy(
            r#"
            //- /lib.rs
            fn caller1() {
                call<|>er2();
            }

            fn caller2() {
                caller3();
            }

            fn caller3() {

            }
            "#,
            "caller2 FN_DEF FileId(1) [32; 63) [35; 42)",
            &["caller1 FN_DEF FileId(1) [0; 31) [3; 10) : [[19; 26)]"],
            &["caller3 FN_DEF FileId(1) [64; 80) [67; 74) : [[51; 58)]"],
        );
    }
}
<|endoftext|>


<commit_before>extern crate native-tls;<commit_msg>Typo in crate name<commit_after>extern crate native_tls;<|endoftext|>


<commit_before>
type InterruptHandlerFn = unsafe extern "C" fn() -> !;

use dispatch_table::{DispatchTable, DispatchFn};
use spin::RwLock;

#[derive(Default)]
#[repr(packed)]
struct IDTEntry {
    base_low: u16,
    selector: u16,
    always0: u8,
    flags: u8,
    base_high: u16,
    base_highest: u32,
    _reserved: u32,
}

#[derive(Default)]
pub struct IDT([IDTEntry; 20]);

lazy_static! {
    static ref INTERRUPT_TABLE: RwLock<DispatchTable<u64, InterruptCPUState>> = RwLock::new(DispatchTable::new(256));
    static ref DESCRIPTOR_TABLE: RwLock<IDT> = RwLock::new(Default::default());
}

impl IDT {
    fn set_entry(&mut self, num: usize, base: u64, selector: u16, flags: u8) {
        self.0[num].base_low = (base & 0xffff) as u16;
        self.0[num].base_high = ((base >> 16) & 0xffff) as u16;
        self.0[num].base_highest = (base >> 32) as u32;
        self.0[num].always0 = 0;
        self.0[num].selector = selector;
        self.0[num].flags = flags;
    }
}

#[repr(C)]
pub struct InterruptCPUState {
    ds: u64,
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rdi: u64,
    rsi: u64,
    rbp: u64,
    rdx: u64,
    rcx: u64,
    rbx: u64,
    rax: u64,
    interrupt_number: u64,
    error_code: u64,
    rip: u64,
    cs: u64,
    rflags: u64,
    rsp: u64,
    ss: u64,
}

pub fn register_interrupt_handler(interrupt: u64,
                                  stub: InterruptHandlerFn,
                                  handler: DispatchFn<u64, InterruptCPUState>) {
    INTERRUPT_TABLE.write().register(interrupt, handler);
    DESCRIPTOR_TABLE.write().set_entry(interrupt as usize, stub as u64, 0x08, 0x8e);
}

pub fn unregister_interrupt_handler(interrupt: u64) {
    INTERRUPT_TABLE.write().unregister(interrupt);
}

#[no_mangle]
pub extern "C" fn dispatch_interrupt(state: &mut InterruptCPUState) {
    INTERRUPT_TABLE.read().dispatch(state.interrupt_number, state);
}

fn default_handler(_interrupt_number: u64, _regs: &mut InterruptCPUState) -> bool {
    true
}

extern "C" {
    fn _isr0() -> !;
    fn _isr1() -> !;
    fn _isr2() -> !;
    fn _isr3() -> !;
    fn _isr4() -> !;
    fn _isr5() -> !;
    fn _isr6() -> !;
    fn _isr7() -> !;
    fn _isr8() -> !;
    fn _isr9() -> !;
    fn _isr10() -> !;
    fn _isr11() -> !;
    fn _isr12() -> !;
    fn _isr13() -> !;
    fn _isr14() -> !;
    fn _isr15() -> !;
    fn _isr16() -> !;
    fn _isr17() -> !;
    fn _isr18() -> !;
    fn _isr19() -> !;
}

const ISR: [InterruptHandlerFn; 20] = [_isr0, _isr1, _isr2, _isr3, _isr4, _isr5, _isr6, _isr7,
                                       _isr8, _isr9, _isr10, _isr11, _isr12, _isr13, _isr14,
                                       _isr15, _isr16, _isr17, _isr18, _isr19];

pub fn init_interrupt_handlers() {
    for i in 0..20 {
        register_interrupt_handler(i, ISR[i as usize], default_handler);
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {

    use interrupts;
    use vmx;
    use cli;
    use core::mem;

    fn new_host_idt_descriptor() -> vmx::CPUTableDescriptor {
        let base = (*interrupts::DESCRIPTOR_TABLE.write()).0.as_ptr() as u64;
        vmx::CPUTableDescriptor {
            base: base,
            limit: (mem::size_of::<interrupts::IDT>() - 1) as u16,
        }
    }

    pub fn run() {
        test_load_and_restore_idt();
    }

    fn test_load_and_restore_idt() {
        cli::ClearLocalInterruptsGuard::new();
        let idt_desc = new_host_idt_descriptor();
        let mut orig_idt_desc: vmx::CPUTableDescriptor = Default::default();
        vmx::sidt(&mut orig_idt_desc);
        vmx::lidt(&idt_desc);
        vmx::lidt(&orig_idt_desc);
    }

    /*
    fn division_by_zero_handler() {

    }

    fn test_divide_by_zero_interrupt() {
        let mut orig_idt_desc: vmx::CPUTableDescriptor = Default::default();

        {
            cli::ClearLocalInterruptsGuard::new();
            let idt_desc = new_host_idt_descriptor();
            vmx::lidt(&idt_desc);
        }

        let a = 10;
        let b = 0;
        let c = a / b; // Division by zero interrupt

    }
    */
}
<commit_msg>Cargo fmt literally crashes on lines over 100 char<commit_after>
type InterruptHandlerFn = unsafe extern "C" fn() -> !;

use dispatch_table::{DispatchTable, DispatchFn};
use spin::RwLock;

#[derive(Default)]
#[repr(packed)]
struct IDTEntry {
    base_low: u16,
    selector: u16,
    always0: u8,
    flags: u8,
    base_high: u16,
    base_highest: u32,
    _reserved: u32,
}

#[derive(Default)]
pub struct IDT([IDTEntry; 20]);

lazy_static! {
    static ref INTERRUPT_TABLE: RwLock<DispatchTable<u64, InterruptCPUState>> =
        RwLock::new(DispatchTable::new(256));
    static ref DESCRIPTOR_TABLE: RwLock<IDT> = RwLock::new(Default::default());
}

impl IDT {
    fn set_entry(&mut self, num: usize, base: u64, selector: u16, flags: u8) {
        self.0[num].base_low = (base & 0xffff) as u16;
        self.0[num].base_high = ((base >> 16) & 0xffff) as u16;
        self.0[num].base_highest = (base >> 32) as u32;
        self.0[num].always0 = 0;
        self.0[num].selector = selector;
        self.0[num].flags = flags;
    }
}

#[repr(C)]
pub struct InterruptCPUState {
    ds: u64,
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rdi: u64,
    rsi: u64,
    rbp: u64,
    rdx: u64,
    rcx: u64,
    rbx: u64,
    rax: u64,
    interrupt_number: u64,
    error_code: u64,
    rip: u64,
    cs: u64,
    rflags: u64,
    rsp: u64,
    ss: u64,
}

pub fn register_interrupt_handler(interrupt: u64,
                                  stub: InterruptHandlerFn,
                                  handler: DispatchFn<u64, InterruptCPUState>) {
    INTERRUPT_TABLE.write().register(interrupt, handler);
    DESCRIPTOR_TABLE.write().set_entry(interrupt as usize, stub as u64, 0x08, 0x8e);
}

pub fn unregister_interrupt_handler(interrupt: u64) {
    INTERRUPT_TABLE.write().unregister(interrupt);
}

#[no_mangle]
pub extern "C" fn dispatch_interrupt(state: &mut InterruptCPUState) {
    INTERRUPT_TABLE.read().dispatch(state.interrupt_number, state);
}

fn default_handler(_interrupt_number: u64, _regs: &mut InterruptCPUState) -> bool {
    true
}

extern "C" {
    fn _isr0() -> !;
    fn _isr1() -> !;
    fn _isr2() -> !;
    fn _isr3() -> !;
    fn _isr4() -> !;
    fn _isr5() -> !;
    fn _isr6() -> !;
    fn _isr7() -> !;
    fn _isr8() -> !;
    fn _isr9() -> !;
    fn _isr10() -> !;
    fn _isr11() -> !;
    fn _isr12() -> !;
    fn _isr13() -> !;
    fn _isr14() -> !;
    fn _isr15() -> !;
    fn _isr16() -> !;
    fn _isr17() -> !;
    fn _isr18() -> !;
    fn _isr19() -> !;
}

const ISR: [InterruptHandlerFn; 20] = [_isr0, _isr1, _isr2, _isr3, _isr4, _isr5, _isr6, _isr7,
                                       _isr8, _isr9, _isr10, _isr11, _isr12, _isr13, _isr14,
                                       _isr15, _isr16, _isr17, _isr18, _isr19];

pub fn init_interrupt_handlers() {
    for i in 0..20 {
        register_interrupt_handler(i, ISR[i as usize], default_handler);
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {

    use interrupts;
    use vmx;
    use cli;
    use core::mem;

    fn new_host_idt_descriptor() -> vmx::CPUTableDescriptor {
        let base = (*interrupts::DESCRIPTOR_TABLE.write()).0.as_ptr() as u64;
        vmx::CPUTableDescriptor {
            base: base,
            limit: (mem::size_of::<interrupts::IDT>() - 1) as u16,
        }
    }

    pub fn run() {
        test_load_and_restore_idt();
    }

    fn test_load_and_restore_idt() {
        cli::ClearLocalInterruptsGuard::new();
        let idt_desc = new_host_idt_descriptor();
        let mut orig_idt_desc: vmx::CPUTableDescriptor = Default::default();
        vmx::sidt(&mut orig_idt_desc);
        vmx::lidt(&idt_desc);
        vmx::lidt(&orig_idt_desc);
    }

    /*
    fn division_by_zero_handler() {

    }

    fn test_divide_by_zero_interrupt() {
        let mut orig_idt_desc: vmx::CPUTableDescriptor = Default::default();

        {
            cli::ClearLocalInterruptsGuard::new();
            let idt_desc = new_host_idt_descriptor();
            vmx::lidt(&idt_desc);
        }

        let a = 10;
        let b = 0;
        let c = a / b; // Division by zero interrupt

    }
    */
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::thread;

use std::sync::mpsc::{Receiver, Sender, channel};
use time;
use std::convert::AsRef;

use hook_configuration::HookConfiguration;
use deployer::{DeployMessage, Deployer};
use tools::to_string;

pub struct Dispatcher {
  pub config: HookConfiguration,
}

impl Dispatcher {
  pub fn run(&self, rx: Receiver<DeployMessage>) {
    let mut to_workers: HashMap<String, Sender<DeployMessage>> = HashMap::new();
    let mut workers: HashMap<String, Deployer> = HashMap::new();
    for conf in &self.config.hooks {

      let worker = Deployer{
        name: conf.worker_name(),
        conf: conf.action.clone(),
        slack: (&self).config.slack.clone(),
      };
      workers.insert(conf.name.clone(), worker);
    }

    for (name, worker) in workers.into_iter() {
      let (tx, rx) = channel();
      to_workers.insert(name.clone(), tx);

      thread::spawn(move || {
        worker.run(rx);
      });
    }

    self.log("Starting dispatcher.");
    while let Ok(data) = rx.recv() {
      match data {
        DeployMessage::Deploy(hk) => {
          let wname = hk.worker_name();
          self.log(format!("Want to deploy {}.", wname).as_ref());
          match to_workers.get(&wname).unwrap().send(DeployMessage::Deploy(hk)) {
            Err(e) => println!("[{}][system] Send to deployer {} failed: {}.", to_string(time::now()), wname, e.to_string() ),
            _ => {}
          }
        },
        DeployMessage::Exit => println!("We should exit."),
      }
    }
    self.log("Stopping dispatcher.");
  }

  fn name(&self) -> String {
    "dispatcher".to_string()
  }

  fn log(&self, info: &str) {
    println!("[{}][{}][system] {}", to_string(time::now()), self.name(), info);
  }

}
<commit_msg>Use worker name, please<commit_after>use std::collections::HashMap;
use std::thread;

use std::sync::mpsc::{Receiver, Sender, channel};
use time;
use std::convert::AsRef;

use hook_configuration::HookConfiguration;
use deployer::{DeployMessage, Deployer};
use tools::to_string;

pub struct Dispatcher {
  pub config: HookConfiguration,
}

impl Dispatcher {
  pub fn run(&self, rx: Receiver<DeployMessage>) {
    let mut to_workers: HashMap<String, Sender<DeployMessage>> = HashMap::new();
    let mut workers: HashMap<String, Deployer> = HashMap::new();
    for conf in &self.config.hooks {

      let worker = Deployer{
        name: conf.worker_name(),
        conf: conf.action.clone(),
        slack: (&self).config.slack.clone(),
      };
      workers.insert(conf.worker_name(), worker);
    }

    for (name, worker) in workers.into_iter() {
      let (tx, rx) = channel();
      to_workers.insert(name.clone(), tx);

      thread::spawn(move || {
        worker.run(rx);
      });
    }

    self.log("Starting dispatcher.");
    while let Ok(data) = rx.recv() {
      match data {
        DeployMessage::Deploy(hk) => {
          let wname = hk.worker_name();
          self.log(format!("Want to deploy {}.", wname).as_ref());
          match to_workers.get(&wname).unwrap().send(DeployMessage::Deploy(hk)) {
            Err(e) => println!("[{}][system] Send to deployer {} failed: {}.", to_string(time::now()), wname, e.to_string() ),
            _ => {}
          }
        },
        DeployMessage::Exit => println!("We should exit."),
      }
    }
    self.log("Stopping dispatcher.");
  }

  fn name(&self) -> String {
    "dispatcher".to_string()
  }

  fn log(&self, info: &str) {
    println!("[{}][{}][system] {}", to_string(time::now()), self.name(), info);
  }

}
<|endoftext|>


<commit_before>use crate::{Distribution, Float, InverseGaussian, Standard, StandardNormal};
use rand::Rng;

/// Error type returned from `NormalInverseGaussian::new`
#[derive(Debug, PartialEq)]
pub enum Error {
    /// `alpha <= 0` or `nan`.
    AlphaNegativeOrNull,
    /// `|beta| >= alpha` or `nan`.
    AbsoluteBetaNotLessThanAlpha,
}

/// The [normal-inverse Gaussian distribution](https://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution)
#[derive(Debug)]
pub struct NormalInverseGaussian<N> {
    alpha: N,
    beta: N,
    inverse_gaussian: InverseGaussian<N>,
}

impl<N: Float> NormalInverseGaussian<N>
where StandardNormal: Distribution<N>
{
    /// Construct a new `NormalInverseGaussian` distribution with the given alpha (tail heaviness) and
    /// beta (asymmetry) parameters.
    pub fn new(alpha: N, beta: N) -> Result<NormalInverseGaussian<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaNegativeOrNull);
        }

        if !(beta.abs() < alpha) {
            return Err(Error::AbsoluteBetaLessThanAlpha);
        }

        let gamma = (alpha * alpha - beta * beta).sqrt();

        let mu = N::from(1.) / gamma;

        let inverse_gaussian = InverseGaussian::new(mu, N::from(1.)).unwrap();

        Ok(Self {
            alpha,
            beta,
            inverse_gaussian,
        })
    }
}

impl<N: Float> Distribution<N> for NormalInverseGaussian<N>
where
    StandardNormal: Distribution<N>,
    Standard: Distribution<N>,
{
    fn sample<R>(&self, rng: &mut R) -> N
    where R: Rng + ?Sized {
        let inv_gauss = rng.sample(&self.inverse_gaussian);

        self.beta * inv_gauss + inv_gauss.sqrt() * rng.sample(StandardNormal)
    }
}

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

    #[test]
    fn test_normal_inverse_gaussian() {
        let norm_inv_gauss = NormalInverseGaussian::new(2.0, 1.0).unwrap();
        let mut rng = crate::test::rng(210);
        for _ in 0..1000 {
            norm_inv_gauss.sample(&mut rng);
        }
    }

    #[test]
    fn test_normal_inverse_gaussian_invalid_param() {
        assert!(NormalInverseGaussian::new(-1.0, 1.0).is_err());
        assert!(NormalInverseGaussian::new(-1.0, -1.0).is_err());
        assert!(NormalInverseGaussian::new(1.0, 2.0).is_err());
        assert!(NormalInverseGaussian::new(2.0, 1.0).is_ok());
    }

    #[test]
    fn value_stability() {
        fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>(
            distr: D, zero: N, expected: &[N],
        ) {
            let mut rng = crate::test::rng(213);
            let mut buf = [zero; 4];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(buf, expected);
        }

        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f32, &[
            0.6568966, 1.3744819, 2.216063, 0.11488572,
        ]);
        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f64, &[
            0.6838707059642927,
            2.4447306460569784,
            0.2361045023235968,
            1.7774534624785319,
        ]);
    }
}
<commit_msg>Fix error variant name<commit_after>use crate::{Distribution, Float, InverseGaussian, Standard, StandardNormal};
use rand::Rng;

/// Error type returned from `NormalInverseGaussian::new`
#[derive(Debug, PartialEq)]
pub enum Error {
    /// `alpha <= 0` or `nan`.
    AlphaNegativeOrNull,
    /// `|beta| >= alpha` or `nan`.
    AbsoluteBetaNotLessThanAlpha,
}

/// The [normal-inverse Gaussian distribution](https://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution)
#[derive(Debug)]
pub struct NormalInverseGaussian<N> {
    alpha: N,
    beta: N,
    inverse_gaussian: InverseGaussian<N>,
}

impl<N: Float> NormalInverseGaussian<N>
where StandardNormal: Distribution<N>
{
    /// Construct a new `NormalInverseGaussian` distribution with the given alpha (tail heaviness) and
    /// beta (asymmetry) parameters.
    pub fn new(alpha: N, beta: N) -> Result<NormalInverseGaussian<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaNegativeOrNull);
        }

        if !(beta.abs() < alpha) {
            return Err(Error::AbsoluteBetaNotLessThanAlpha);
        }

        let gamma = (alpha * alpha - beta * beta).sqrt();

        let mu = N::from(1.) / gamma;

        let inverse_gaussian = InverseGaussian::new(mu, N::from(1.)).unwrap();

        Ok(Self {
            alpha,
            beta,
            inverse_gaussian,
        })
    }
}

impl<N: Float> Distribution<N> for NormalInverseGaussian<N>
where
    StandardNormal: Distribution<N>,
    Standard: Distribution<N>,
{
    fn sample<R>(&self, rng: &mut R) -> N
    where R: Rng + ?Sized {
        let inv_gauss = rng.sample(&self.inverse_gaussian);

        self.beta * inv_gauss + inv_gauss.sqrt() * rng.sample(StandardNormal)
    }
}

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

    #[test]
    fn test_normal_inverse_gaussian() {
        let norm_inv_gauss = NormalInverseGaussian::new(2.0, 1.0).unwrap();
        let mut rng = crate::test::rng(210);
        for _ in 0..1000 {
            norm_inv_gauss.sample(&mut rng);
        }
    }

    #[test]
    fn test_normal_inverse_gaussian_invalid_param() {
        assert!(NormalInverseGaussian::new(-1.0, 1.0).is_err());
        assert!(NormalInverseGaussian::new(-1.0, -1.0).is_err());
        assert!(NormalInverseGaussian::new(1.0, 2.0).is_err());
        assert!(NormalInverseGaussian::new(2.0, 1.0).is_ok());
    }

    #[test]
    fn value_stability() {
        fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>(
            distr: D, zero: N, expected: &[N],
        ) {
            let mut rng = crate::test::rng(213);
            let mut buf = [zero; 4];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(buf, expected);
        }

        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f32, &[
            0.6568966, 1.3744819, 2.216063, 0.11488572,
        ]);
        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f64, &[
            0.6838707059642927,
            2.4447306460569784,
            0.2361045023235968,
            1.7774534624785319,
        ]);
    }
}
<|endoftext|>


<commit_before>use lib::*;
use ser::{Error, Impossible, Serialize, Serializer};

impl Error for fmt::Error {
    fn custom<T: Display>(_msg: T) -> Self {
        fmt::Error
    }
}

macro_rules! fmt_primitives {
    ($($f:ident: $t:ty,)*) => {
        $(
            fn $f(self, v: $t) -> fmt::Result {
                write!(self, "{}", v)
            }
        )*
    };
}

impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
    type Ok = ();
    type Error = fmt::Error;
    type SerializeSeq = Impossible<(), fmt::Error>;
    type SerializeTuple = Impossible<(), fmt::Error>;
    type SerializeTupleStruct = Impossible<(), fmt::Error>;
    type SerializeTupleVariant = Impossible<(), fmt::Error>;
    type SerializeMap = Impossible<(), fmt::Error>;
    type SerializeStruct = Impossible<(), fmt::Error>;
    type SerializeStructVariant = Impossible<(), fmt::Error>;

    fmt_primitives! {
        serialize_bool: bool,
        serialize_i8: i8,
        serialize_i16: i16,
        serialize_i32: i32,
        serialize_i64: i64,
        serialize_u8: u8,
        serialize_u16: u16,
        serialize_u32: u32,
        serialize_u64: u64,
        serialize_f32: f32,
        serialize_f64: f64,
        serialize_char: char,
        serialize_str: &str,
        serialize_unit_struct: &'static str,
    }

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> fmt::Result {
        write!(self, "{}", variant)
    }

    fn serialize_bytes(self, _v: &[u8]) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_none(self) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_some<T: ?Sized>(self, _value: &T) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_unit(self) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, _value: &T) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_newtype_variant<T: ?Sized>(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _value: &T,
    ) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleStruct, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleVariant, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStruct, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, fmt::Error> {
        Err(fmt::Error)
    }

    fn collect_str<T: ?Sized>(self, value: &T) -> fmt::Result
    where
        T: Display,
    {
        Display::fmt(value, self)
    }
}
<commit_msg>Directly display to the Formatter<commit_after>use lib::*;
use ser::{Error, Impossible, Serialize, Serializer};

impl Error for fmt::Error {
    fn custom<T: Display>(_msg: T) -> Self {
        fmt::Error
    }
}

macro_rules! fmt_primitives {
    ($($f:ident: $t:ty,)*) => {
        $(
            fn $f(self, v: $t) -> fmt::Result {
                Display::fmt(&v, self)
            }
        )*
    };
}

impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
    type Ok = ();
    type Error = fmt::Error;
    type SerializeSeq = Impossible<(), fmt::Error>;
    type SerializeTuple = Impossible<(), fmt::Error>;
    type SerializeTupleStruct = Impossible<(), fmt::Error>;
    type SerializeTupleVariant = Impossible<(), fmt::Error>;
    type SerializeMap = Impossible<(), fmt::Error>;
    type SerializeStruct = Impossible<(), fmt::Error>;
    type SerializeStructVariant = Impossible<(), fmt::Error>;

    fmt_primitives! {
        serialize_bool: bool,
        serialize_i8: i8,
        serialize_i16: i16,
        serialize_i32: i32,
        serialize_i64: i64,
        serialize_u8: u8,
        serialize_u16: u16,
        serialize_u32: u32,
        serialize_u64: u64,
        serialize_f32: f32,
        serialize_f64: f64,
        serialize_char: char,
        serialize_str: &str,
        serialize_unit_struct: &'static str,
    }

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> fmt::Result {
        Display::fmt(variant, self)
    }

    fn serialize_bytes(self, _v: &[u8]) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_none(self) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_some<T: ?Sized>(self, _value: &T) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_unit(self) -> fmt::Result {
        Err(fmt::Error)
    }

    fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, _value: &T) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_newtype_variant<T: ?Sized>(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _value: &T,
    ) -> fmt::Result
    where
        T: Serialize,
    {
        Err(fmt::Error)
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleStruct, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeTupleVariant, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStruct, fmt::Error> {
        Err(fmt::Error)
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, fmt::Error> {
        Err(fmt::Error)
    }

    fn collect_str<T: ?Sized>(self, value: &T) -> fmt::Result
    where
        T: Display,
    {
        Display::fmt(value, self)
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{IntoIter, Iter, IterMut};
use std::collections::HashMap;
use std::iter::FromIterator;

#[derive(Debug, Clone)]
pub struct Extensions(HashMap<String, String>);

impl Extensions {
    pub fn insert(&mut self, param: String, value: String) -> Option<String> {
        self.0.insert(param, value)
    }

    pub fn remove(&mut self, param: String) -> Option<String> {
        self.0.remove(param.as_str())
    }

    pub fn iter(&self) -> Iter<String, String> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<String, String> {
        self.0.iter_mut()
    }

    pub fn into_inner(self) -> HashMap<String, String> {
        self.0
    }
}

impl ToString for Extensions {
    fn to_string(&self) -> String {
        use crate::encoding::encode;
        use std::borrow::Cow;

        self.iter()
            .map(|(k, v)| [encode(k), Cow::Borrowed("="), encode(v)].concat())
            .collect::<Vec<_>>()
            .join("&")
    }
}

impl From<HashMap<String, String>> for Extensions {
    fn from(h: HashMap<String, String>) -> Self {
        Self(h)
    }
}

impl Extend<(String, String)> for Extensions {
    fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
        self.0.extend(iter);
    }
}

impl FromIterator<(String, String)> for Extensions {
    fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
        Self(HashMap::from_iter(iter))
    }
}

impl<'a> IntoIterator for &'a Extensions {
    type Item = (&'a String, &'a String);
    type IntoIter = Iter<'a, String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a> IntoIterator for &'a mut Extensions {
    type Item = (&'a String, &'a mut String);
    type IntoIter = IterMut<'a, String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl IntoIterator for Extensions {
    type Item = (String, String);
    type IntoIter = IntoIter<String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}
<commit_msg>extensions: hide internal implementation and make the API more ergonomic<commit_after>use std::collections::hash_map::{IntoIter, Iter, IterMut};
use std::collections::HashMap;
use std::iter::FromIterator;

#[derive(Debug, Clone)]
pub struct Extensions(HashMap<String, String>);

impl Extensions {
    pub fn new() -> Self {
        Extensions(HashMap::new())
    }

    pub fn insert<S: Into<String>>(&mut self, param: S, value: S) -> Option<String> {
        self.0.insert(param.into(), value.into())
    }

    pub fn remove<R: AsRef<String>, S: Into<R>>(&mut self, param: S) -> Option<String> {
        self.0.remove(param.into().as_ref())
    }

    pub fn iter(&self) -> Iter<String, String> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<String, String> {
        self.0.iter_mut()
    }

    pub fn into_inner(self) -> HashMap<String, String> {
        self.0
    }
}

impl ToString for Extensions {
    fn to_string(&self) -> String {
        use crate::encoding::encode;
        use std::borrow::Cow;

        self.iter()
            .map(|(k, v)| [encode(k), Cow::Borrowed("="), encode(v)].concat())
            .collect::<Vec<_>>()
            .join("&")
    }
}

impl From<HashMap<String, String>> for Extensions {
    fn from(h: HashMap<String, String>) -> Self {
        Self(h)
    }
}

impl Extend<(String, String)> for Extensions {
    fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
        self.0.extend(iter);
    }
}

impl FromIterator<(String, String)> for Extensions {
    fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
        Self(HashMap::from_iter(iter))
    }
}

impl<'a> IntoIterator for &'a Extensions {
    type Item = (&'a String, &'a String);
    type IntoIter = Iter<'a, String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a> IntoIterator for &'a mut Extensions {
    type Item = (&'a String, &'a mut String);
    type IntoIter = IterMut<'a, String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl IntoIterator for Extensions {
    type Item = (String, String);
    type IntoIter = IntoIter<String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}
<|endoftext|>


<commit_before>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!(
        "## Running compile-fail tests in {} against miri for target {}",
        path,
        target
    );
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    let mut flags = Vec::new();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    flags.push("-Zmir-emit-validate=1".to_owned());
    config.target_rustcflags = Some(flags.join(" "));
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    if let Some(rustc_path) = rustc_test_suite() {
        config.rustc_path = rustc_path;
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
        config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
    } else {
        config.target_rustcflags = Some("-Dwarnings".to_owned());
    }
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    );
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    let mut flags = Vec::new();
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
        // For now, only validate without optimizations.  Inlining breaks validation.
        flags.push("-Zmir-emit-validate=1".to_owned());
    }
    if target == host {
        flags.push("--miri_host_target".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    compiletest::run_tests(&config);
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) {
            continue;
        }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect(
        "no host: part in rustc -vV",
    );
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

fn run_pass_miri(opt: bool) {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        miri_pass("tests/run-pass", &target, &host, false, opt);
    });
    miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
}

#[test]
fn run_pass_miri_noopt() {
    run_pass_miri(false);
}

#[test]
fn run_pass_miri_opt() {
    run_pass_miri(true);
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<commit_msg>disable optimized tests until rustc is fixed<commit_after>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!(
        "## Running compile-fail tests in {} against miri for target {}",
        path,
        target
    );
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    let mut flags = Vec::new();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    flags.push("-Zmir-emit-validate=1".to_owned());
    config.target_rustcflags = Some(flags.join(" "));
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    if let Some(rustc_path) = rustc_test_suite() {
        config.rustc_path = rustc_path;
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
        config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
    } else {
        config.target_rustcflags = Some("-Dwarnings".to_owned());
    }
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    );
    let mut config = compiletest::Config::default().tempdir();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    let mut flags = Vec::new();
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
        // For now, only validate without optimizations.  Inlining breaks validation.
        flags.push("-Zmir-emit-validate=1".to_owned());
    }
    if target == host {
        flags.push("--miri_host_target".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    compiletest::run_tests(&config);
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) {
            continue;
        }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect(
        "no host: part in rustc -vV",
    );
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

fn run_pass_miri(opt: bool) {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        miri_pass("tests/run-pass", &target, &host, false, opt);
    });
    miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
}

#[test]
fn run_pass_miri_noopt() {
    run_pass_miri(false);
}

#[test]
fn run_pass_miri_opt() {
    // FIXME: Disabled for now, as the optimizer is pretty broken and crashes...
    //run_pass_miri(true);
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<|endoftext|>


<commit_before>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn compile_fail(sysroot: &str) {
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = "compile-fail".parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from("tests/compile-fail".to_string());
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn run_pass() {
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from("tests/run-pass".to_string());
    config.target_rustcflags = Some("-Dwarnings".to_string());
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_pass();
    for_all_targets(&sysroot, |target| {
        let files = std::fs::read_dir("tests/run-pass").unwrap();
        let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
            Box::new(files.chain(std::fs::read_dir(path).unwrap()))
        } else {
            Box::new(files)
        };
        let mut mir_not_found = 0;
        let mut crate_not_found = 0;
        let mut success = 0;
        let mut failed = 0;
        for file in files {
            let file = file.unwrap();
            let path = file.path();

            if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
                continue;
            }

            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(path);
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);

            match cmd.output() {
                Ok(ref output) if output.status.success() => {
                    success += 1;
                    writeln!(stderr.lock(), "ok").unwrap()
                },
                Ok(output) => {
                    let output_err = std::str::from_utf8(&output.stderr).unwrap();
                    if let Some(text) = output_err.splitn(2, "thread 'main' panicked at 'no mir for `").nth(1) {
                        mir_not_found += 1;
                        let end = text.find('`').unwrap();
                        writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                    } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                        crate_not_found += 1;
                        let end = text.find('`').unwrap();
                        writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                    } else {
                        failed += 1;
                        writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
                        writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                        writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                    }
                }
                Err(e) => {
                    writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
                    panic!("failed to execute miri");
                },
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap();
        assert_eq!(failed, 0, "some tests failed");
    });
    compile_fail(&sysroot);
}
<commit_msg>fix run-pass test error message parsing<commit_after>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn compile_fail(sysroot: &str) {
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = "compile-fail".parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from("tests/compile-fail".to_string());
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn run_pass() {
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from("tests/run-pass".to_string());
    config.target_rustcflags = Some("-Dwarnings".to_string());
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_pass();
    for_all_targets(&sysroot, |target| {
        let files = std::fs::read_dir("tests/run-pass").unwrap();
        let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
            Box::new(files.chain(std::fs::read_dir(path).unwrap()))
        } else {
            Box::new(files)
        };
        let mut mir_not_found = 0;
        let mut crate_not_found = 0;
        let mut success = 0;
        let mut failed = 0;
        for file in files {
            let file = file.unwrap();
            let path = file.path();

            if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
                continue;
            }

            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(path);
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);

            match cmd.output() {
                Ok(ref output) if output.status.success() => {
                    success += 1;
                    writeln!(stderr.lock(), "ok").unwrap()
                },
                Ok(output) => {
                    let output_err = std::str::from_utf8(&output.stderr).unwrap();
                    if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
                        mir_not_found += 1;
                        let end = text.find('`').unwrap();
                        writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                    } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                        crate_not_found += 1;
                        let end = text.find('`').unwrap();
                        writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                    } else {
                        failed += 1;
                        writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
                        writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                        writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                    }
                }
                Err(e) => {
                    writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
                    panic!("failed to execute miri");
                },
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap();
        assert_eq!(failed, 0, "some tests failed");
    });
    compile_fail(&sysroot);
}
<|endoftext|>