<commit_before>//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default

use crate::utils::{snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Checks for address of operations (`&`) that are going to
    /// be dereferenced immediately by the compiler.
    ///
    /// **Why is this bad?** Suggests that the receiver of the expression borrows
    /// the expression.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let x: &i32 = &&&&&&5;
    ///
    /// // Good
    /// let x: &i32 = &5;
    /// ```
    pub NEEDLESS_BORROW,
    nursery,
    "taking a reference that is going to be automatically dereferenced"
}

#[derive(Default)]
pub struct NeedlessBorrow {
    derived_item: Option<HirId>,
}

impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);

impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if e.span.from_expansion() || self.derived_item.is_some() {
            return;
        }
        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
                for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
                    if let [Adjustment {
                        kind: Adjust::Deref(_), ..
                    }, Adjustment {
                        kind: Adjust::Deref(_), ..
                    }, Adjustment {
                        kind: Adjust::Borrow(_),
                        ..
                    }] = *adj3
                    {
                        span_lint_and_then(
                            cx,
                            NEEDLESS_BORROW,
                            e.span,
                            &format!(
                                "this expression borrows a reference (`&{}`) that is immediately dereferenced \
                             by the compiler",
                                ty
                            ),
                            |diag| {
                                if let Some(snippet) = snippet_opt(cx, inner.span) {
                                    diag.span_suggestion(
                                        e.span,
                                        "change this to",
                                        snippet,
                                        Applicability::MachineApplicable,
                                    );
                                }
                            },
                        );
                    }
                }
            }
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
        if pat.span.from_expansion() || self.derived_item.is_some() {
            return;
        }
        if_chain! {
            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
            if mutbl == Mutability::Not;
            if let ty::Ref(_, _, mutbl) = *tam.kind();
            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
            if mutbl == Mutability::Not;
            then {
                span_lint_and_then(
                    cx,
                    NEEDLESS_BORROW,
                    pat.span,
                    "this pattern creates a reference to a reference",
                    |diag| {
                        if let Some(snippet) = snippet_opt(cx, name.span) {
                            diag.span_suggestion(
                                pat.span,
                                "change this to",
                                snippet,
                                Applicability::MachineApplicable,
                            );
                        }
                    }
                )
            }
        }
    }

    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) {
            debug_assert!(self.derived_item.is_none());
            self.derived_item = Some(item.hir_id);
        }
    }

    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if let Some(id) = self.derived_item {
            if item.hir_id == id {
                self.derived_item = None;
            }
        }
    }
}
<commit_msg>Use existing 'is_automatically_derived' helper<commit_after>//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default

use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::{declare_tool_lint, impl_lint_pass};

declare_clippy_lint! {
    /// **What it does:** Checks for address of operations (`&`) that are going to
    /// be dereferenced immediately by the compiler.
    ///
    /// **Why is this bad?** Suggests that the receiver of the expression borrows
    /// the expression.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let x: &i32 = &&&&&&5;
    ///
    /// // Good
    /// let x: &i32 = &5;
    /// ```
    pub NEEDLESS_BORROW,
    nursery,
    "taking a reference that is going to be automatically dereferenced"
}

#[derive(Default)]
pub struct NeedlessBorrow {
    derived_item: Option<HirId>,
}

impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);

impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if e.span.from_expansion() || self.derived_item.is_some() {
            return;
        }
        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
                for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
                    if let [Adjustment {
                        kind: Adjust::Deref(_), ..
                    }, Adjustment {
                        kind: Adjust::Deref(_), ..
                    }, Adjustment {
                        kind: Adjust::Borrow(_),
                        ..
                    }] = *adj3
                    {
                        span_lint_and_then(
                            cx,
                            NEEDLESS_BORROW,
                            e.span,
                            &format!(
                                "this expression borrows a reference (`&{}`) that is immediately dereferenced \
                             by the compiler",
                                ty
                            ),
                            |diag| {
                                if let Some(snippet) = snippet_opt(cx, inner.span) {
                                    diag.span_suggestion(
                                        e.span,
                                        "change this to",
                                        snippet,
                                        Applicability::MachineApplicable,
                                    );
                                }
                            },
                        );
                    }
                }
            }
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
        if pat.span.from_expansion() || self.derived_item.is_some() {
            return;
        }
        if_chain! {
            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
            if mutbl == Mutability::Not;
            if let ty::Ref(_, _, mutbl) = *tam.kind();
            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
            if mutbl == Mutability::Not;
            then {
                span_lint_and_then(
                    cx,
                    NEEDLESS_BORROW,
                    pat.span,
                    "this pattern creates a reference to a reference",
                    |diag| {
                        if let Some(snippet) = snippet_opt(cx, name.span) {
                            diag.span_suggestion(
                                pat.span,
                                "change this to",
                                snippet,
                                Applicability::MachineApplicable,
                            );
                        }
                    }
                )
            }
        }
    }

    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if is_automatically_derived(item.attrs) {
            debug_assert!(self.derived_item.is_none());
            self.derived_item = Some(item.hir_id);
        }
    }

    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if let Some(id) = self.derived_item {
            if item.hir_id == id {
                self.derived_item = None;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

extern crate byteorder;
extern crate kvm;
extern crate kvm_sys;
extern crate libc;
#[macro_use]
extern crate logger;
extern crate memory_model;
extern crate sys_util;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
mod bootparam;
// Bindgen didn't implement copy for boot_params because edid_info contains an array with len > 32.
impl Copy for bootparam::edid_info {}
impl Clone for bootparam::edid_info {
    fn clone(&self) -> Self {
        *self
    }
}
impl Copy for bootparam::boot_params {}
impl Clone for bootparam::boot_params {
    fn clone(&self) -> Self {
        *self
    }
}
// boot_params is just a series of ints, it is safe to initialize it.
unsafe impl memory_model::DataInit for bootparam::boot_params {}

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
mod msr_index;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
mod mpspec;
// These mpspec types are only data, reading them from data is a safe initialization.
unsafe impl memory_model::DataInit for mpspec::mpc_bus {}
unsafe impl memory_model::DataInit for mpspec::mpc_cpu {}
unsafe impl memory_model::DataInit for mpspec::mpc_intsrc {}
unsafe impl memory_model::DataInit for mpspec::mpc_ioapic {}
unsafe impl memory_model::DataInit for mpspec::mpc_table {}
unsafe impl memory_model::DataInit for mpspec::mpc_lintsrc {}
unsafe impl memory_model::DataInit for mpspec::mpf_intel {}

pub mod cpuid;
mod gdt;
pub mod interrupts;
pub mod layout;
mod mptable;
pub mod regs;

use std::mem;
use std::result;

use bootparam::boot_params;
use bootparam::E820_RAM;
use memory_model::{GuestAddress, GuestMemory};

pub use interrupts::Error as IntError;
pub use mptable::Error as MpTableError;
pub use regs::Error as RegError;

#[derive(Debug)]
pub enum Error {
    /// Error writing MP table to memory.
    MpTableSetup(MpTableError),
    /// Error writing the zero page of guest memory.
    ZeroPageSetup,
    /// The zero page extends past the end of guest_mem.
    ZeroPagePastRamEnd,
    /// Invalid e820 setup params.
    E820Configuration,
}
pub type Result<T> = result::Result<T, Error>;

const MEM_32BIT_GAP_SIZE: usize = (768 << 20);
const FIRST_ADDR_PAST_32BITS: usize = (1 << 32);

/// Returns a Vec of the valid memory addresses.
/// These should be used to configure the GuestMemory structure for the platfrom.
/// For x86_64 all addresses are valid from the start of the kenel except a
/// carve out at the end of 32bit address space.
pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
    let memory_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
    let memory_gap_end = GuestAddress(FIRST_ADDR_PAST_32BITS);
    let requested_memory_size = GuestAddress(size);
    let mut regions = Vec::new();

    // case1: guest memory fits before the gap
    if requested_memory_size <= memory_gap_start {
        regions.push((GuestAddress(0), size));
    // case2: guest memory extends beyond the gap
    } else {
        // push memory before the gap
        regions.push((GuestAddress(0), memory_gap_start.offset()));
        regions.push((
            memory_gap_end,
            requested_memory_size.offset_from(memory_gap_start),
        ));
    }

    regions
}

pub fn get_32bit_gap_start() -> usize {
    FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE
}

/// Configures the system and should be called once per vm before starting vcpu threads.
///
/// # Arguments
///
/// * `guest_mem` - The memory to be used by the guest.
/// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded.
/// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator.
/// * `num_cpus` - Number of virtual CPUs the guest will have.
pub fn configure_system(
    guest_mem: &GuestMemory,
    cmdline_addr: GuestAddress,
    cmdline_size: usize,
    num_cpus: u8,
) -> Result<()> {
    const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
    const KERNEL_HDR_MAGIC: u32 = 0x53726448;
    const KERNEL_LOADER_OTHER: u8 = 0xff;
    const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
    let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS);
    let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
    let himem_start = GuestAddress(layout::HIMEM_START);

    // Note that this puts the mptable at the last 1k of Linux's 640k base RAM
    mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)?;

    let mut params: boot_params = Default::default();

    params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
    params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
    params.hdr.header = KERNEL_HDR_MAGIC;
    params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32;
    params.hdr.cmdline_size = cmdline_size as u32;
    params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;

    add_e820_entry(&mut params, 0, layout::EBDA_START, E820_RAM)?;

    let mem_end = guest_mem.end_addr();
    if mem_end < end_32bit_gap_start {
        add_e820_entry(
            &mut params,
            himem_start.offset() as u64,
            mem_end.offset_from(himem_start) as u64,
            E820_RAM,
        )?;
    } else {
        add_e820_entry(
            &mut params,
            himem_start.offset() as u64,
            end_32bit_gap_start.offset_from(himem_start) as u64,
            E820_RAM,
        )?;
        if mem_end > first_addr_past_32bits {
            add_e820_entry(
                &mut params,
                first_addr_past_32bits.offset() as u64,
                mem_end.offset_from(first_addr_past_32bits) as u64,
                E820_RAM,
            )?;
        }
    }

    let zero_page_addr = GuestAddress(layout::ZERO_PAGE_START);
    guest_mem
        .checked_offset(zero_page_addr, mem::size_of::<boot_params>())
        .ok_or(Error::ZeroPagePastRamEnd)?;
    guest_mem
        .write_obj_at_addr(params, zero_page_addr)
        .map_err(|_| Error::ZeroPageSetup)?;

    Ok(())
}

/// Add an e820 region to the e820 map.
/// Returns Ok(()) if successful, or an error if there is no space left in the map.
fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) -> Result<()> {
    if params.e820_entries >= params.e820_map.len() as u8 {
        return Err(Error::E820Configuration);
    }

    params.e820_map[params.e820_entries as usize].addr = addr;
    params.e820_map[params.e820_entries as usize].size = size;
    params.e820_map[params.e820_entries as usize].type_ = mem_type;
    params.e820_entries += 1;

    Ok(())
}

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

    #[test]
    fn regions_lt_4gb() {
        let regions = arch_memory_regions(1usize << 29);
        assert_eq!(1, regions.len());
        assert_eq!(GuestAddress(0), regions[0].0);
        assert_eq!(1usize << 29, regions[0].1);
    }

    #[test]
    fn regions_gt_4gb() {
        let regions = arch_memory_regions((1usize << 32) + 0x8000);
        assert_eq!(2, regions.len());
        assert_eq!(GuestAddress(0), regions[0].0);
        assert_eq!(GuestAddress(1usize << 32), regions[1].0);
    }
}
<commit_msg>x86_64: unit tests for the overall...<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

extern crate byteorder;
extern crate kvm;
extern crate kvm_sys;
extern crate libc;
#[macro_use]
extern crate logger;
extern crate memory_model;
extern crate sys_util;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
mod bootparam;
// boot_params is just a series of ints, it is safe to initialize it.
unsafe impl memory_model::DataInit for bootparam::boot_params {}

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
mod msr_index;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
mod mpspec;
// These mpspec types are only data, reading them from data is a safe initialization.
unsafe impl memory_model::DataInit for mpspec::mpc_bus {}
unsafe impl memory_model::DataInit for mpspec::mpc_cpu {}
unsafe impl memory_model::DataInit for mpspec::mpc_intsrc {}
unsafe impl memory_model::DataInit for mpspec::mpc_ioapic {}
unsafe impl memory_model::DataInit for mpspec::mpc_table {}
unsafe impl memory_model::DataInit for mpspec::mpc_lintsrc {}
unsafe impl memory_model::DataInit for mpspec::mpf_intel {}

pub mod cpuid;
mod gdt;
pub mod interrupts;
pub mod layout;
mod mptable;
pub mod regs;

use std::mem;
use std::result;

use bootparam::boot_params;
use bootparam::E820_RAM;
use memory_model::{GuestAddress, GuestMemory};

pub use interrupts::Error as IntError;
pub use mptable::Error as MpTableError;
pub use regs::Error as RegError;

#[derive(Debug)]
pub enum Error {
    /// Invalid e820 setup params.
    E820Configuration,
    /// Error writing MP table to memory.
    MpTableSetup(MpTableError),
    /// The zero page extends past the end of guest_mem.
    ZeroPagePastRamEnd,
    /// Error writing the zero page of guest memory.
    ZeroPageSetup,
}
pub type Result<T> = result::Result<T, Error>;

const FIRST_ADDR_PAST_32BITS: usize = (1 << 32);
const MEM_32BIT_GAP_SIZE: usize = (768 << 20);

/// Returns a Vec of the valid memory addresses.
/// These should be used to configure the GuestMemory structure for the platform.
/// For x86_64 all addresses are valid from the start of the kernel except a
/// carve out at the end of 32bit address space.
pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> {
    let memory_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
    let memory_gap_end = GuestAddress(FIRST_ADDR_PAST_32BITS);
    let requested_memory_size = GuestAddress(size);
    let mut regions = Vec::new();

    // case1: guest memory fits before the gap
    if requested_memory_size <= memory_gap_start {
        regions.push((GuestAddress(0), size));
    // case2: guest memory extends beyond the gap
    } else {
        // push memory before the gap
        regions.push((GuestAddress(0), memory_gap_start.offset()));
        regions.push((
            memory_gap_end,
            requested_memory_size.offset_from(memory_gap_start),
        ));
    }

    regions
}

/// X86 specific memory hole/ memory mapped devices/ reserved area.
///
pub fn get_32bit_gap_start() -> usize {
    FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE
}

/// Configures the system and should be called once per vm before starting vcpu threads.
///
/// # Arguments
///
/// * `guest_mem` - The memory to be used by the guest.
/// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded.
/// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator.
/// * `num_cpus` - Number of virtual CPUs the guest will have.
pub fn configure_system(
    guest_mem: &GuestMemory,
    cmdline_addr: GuestAddress,
    cmdline_size: usize,
    num_cpus: u8,
) -> Result<()> {
    const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
    const KERNEL_HDR_MAGIC: u32 = 0x53726448;
    const KERNEL_LOADER_OTHER: u8 = 0xff;
    const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
    let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS);
    let end_32bit_gap_start = GuestAddress(get_32bit_gap_start());

    let himem_start = GuestAddress(layout::HIMEM_START);

    // Note that this puts the mptable at the last 1k of Linux's 640k base RAM
    mptable::setup_mptable(guest_mem, num_cpus).map_err(Error::MpTableSetup)?;

    let mut params: boot_params = Default::default();

    params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
    params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
    params.hdr.header = KERNEL_HDR_MAGIC;
    params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32;
    params.hdr.cmdline_size = cmdline_size as u32;
    params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;

    add_e820_entry(&mut params, 0, layout::EBDA_START, E820_RAM)?;

    let mem_end = guest_mem.end_addr();
    if mem_end < end_32bit_gap_start {
        add_e820_entry(
            &mut params,
            himem_start.offset() as u64,
            mem_end.offset_from(himem_start) as u64,
            E820_RAM,
        )?;
    } else {
        add_e820_entry(
            &mut params,
            himem_start.offset() as u64,
            end_32bit_gap_start.offset_from(himem_start) as u64,
            E820_RAM,
        )?;
        if mem_end > first_addr_past_32bits {
            add_e820_entry(
                &mut params,
                first_addr_past_32bits.offset() as u64,
                mem_end.offset_from(first_addr_past_32bits) as u64,
                E820_RAM,
            )?;
        }
    }

    let zero_page_addr = GuestAddress(layout::ZERO_PAGE_START);
    guest_mem
        .checked_offset(zero_page_addr, mem::size_of::<boot_params>())
        .ok_or(Error::ZeroPagePastRamEnd)?;
    guest_mem
        .write_obj_at_addr(params, zero_page_addr)
        .map_err(|_| Error::ZeroPageSetup)?;

    Ok(())
}

/// Add an e820 region to the e820 map.
/// Returns Ok(()) if successful, or an error if there is no space left in the map.
fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) -> Result<()> {
    if params.e820_entries >= params.e820_map.len() as u8 {
        return Err(Error::E820Configuration);
    }

    params.e820_map[params.e820_entries as usize].addr = addr;
    params.e820_map[params.e820_entries as usize].size = size;
    params.e820_map[params.e820_entries as usize].type_ = mem_type;
    params.e820_entries += 1;

    Ok(())
}

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

    #[test]
    fn regions_lt_4gb() {
        let regions = arch_memory_regions(1usize << 29);
        assert_eq!(1, regions.len());
        assert_eq!(GuestAddress(0), regions[0].0);
        assert_eq!(1usize << 29, regions[0].1);
    }

    #[test]
    fn regions_gt_4gb() {
        let regions = arch_memory_regions((1usize << 32) + 0x8000);
        assert_eq!(2, regions.len());
        assert_eq!(GuestAddress(0), regions[0].0);
        assert_eq!(GuestAddress(1usize << 32), regions[1].0);
    }

    #[test]
    fn test_32bit_gap() {
        assert_eq!(
            get_32bit_gap_start(),
            FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE
        );
    }

    #[test]
    fn test_system_configuration() {
        let no_vcpus = 4;
        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
        assert!(configure_system(&gm, GuestAddress(0), 0, 1).is_err());

        // Now assigning some memory that falls before the 32bit memory hole.
        let mem_size = 128 << 20;
        let arch_mem_regions = arch_memory_regions(mem_size);
        let gm = GuestMemory::new(&arch_mem_regions).unwrap();
        configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap();

        // Now assigning some memory that is equal to the start of the 32bit memory hole.
        let mem_size = 3328 << 20;
        let arch_mem_regions = arch_memory_regions(mem_size);
        let gm = GuestMemory::new(&arch_mem_regions).unwrap();
        configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap();

        // Now assigning some memory that falls after the 32bit memory hole.
        let mem_size = 3330 << 20;
        let arch_mem_regions = arch_memory_regions(mem_size);
        let gm = GuestMemory::new(&arch_mem_regions).unwrap();
        configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap();
    }

    #[test]
    fn test_add_e820_entry() {
        let e820_map = [(e820entry {
            addr: 0x1,
            size: 4,
            type_: 1,
        }); 128];

        let expected_params = boot_params {
            e820_map,
            e820_entries: 1,
            ..Default::default()
        };

        let mut params: boot_params = Default::default();
        add_e820_entry(
            &mut params,
            e820_map[0].addr,
            e820_map[0].size,
            e820_map[0].type_,
        ).unwrap();
        assert_eq!(
            format!("{:?}", params.e820_map[0]),
            format!("{:?}", expected_params.e820_map[0])
        );
        assert_eq!(params.e820_entries, expected_params.e820_entries);

        // Exercise the scenario where the field storing the length of the e820 entry table is
        // is bigger than the allocated memory.
        params.e820_entries = params.e820_map.len() as u8 + 1;
        assert!(
            add_e820_entry(
                &mut params,
                e820_map[0].addr,
                e820_map[0].size,
                e820_map[0].type_
            ).is_err()
        );
    }
}
<|endoftext|>


<commit_before>use std::{
    env,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let dist = project_root().join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag)?;
        }
        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel)?;
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str) -> Result<()> {
    let _d = pushd("./editors/code")?;
    let nightly = release_tag == "nightly";

    let mut patch = Patch::new("./package.json")?;

    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": false,"#, "")
        .replace(",\n                \"$generated-end\": false", "");

    if nightly {
        patch.replace(
            r#""displayName": "rust-analyzer""#,
            r#""displayName": "rust-analyzer (nightly)""#,
        );
    }
    if !nightly {
        patch.replace(r#""enableProposedApi": true,"#, r#""#);
    }
    patch.commit()?;

    cmd!("npm ci").run()?;
    cmd!("npx vsce package -o ../../dist/rust-analyzer.vsix").run()?;
    Ok(())
}

fn dist_server(release_channel: &str) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let target = get_target();
    if target.contains("-linux-gnu") || target.contains("-linux-musl") {
        env::set_var("CC", "clang");
    }

    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;

    let suffix = exe_suffix(&target);
    let src =
        Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix));
    let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix));
    gzip(&src, &dst.with_extension("gz"))?;

    // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
    // Remove this block after a couple of releases
    match target.as_ref() {
        "x86_64-unknown-linux-gnu" => {
            cp(&src, "dist/rust-analyzer-linux")?;
            gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
        }
        "x86_64-pc-windows-msvc" => {
            cp(&src, "dist/rust-analyzer-windows.exe")?;
            gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
        }
        "x86_64-apple-darwin" => {
            cp(&src, "dist/rust-analyzer-mac")?;
            gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
        }
        _ => {}
    }

    Ok(())
}

fn get_target() -> String {
    match env::var("RA_TARGET") {
        Ok(target) => target,
        _ => {
            if cfg!(target_os = "linux") {
                "x86_64-unknown-linux-gnu".to_string()
            } else if cfg!(target_os = "windows") {
                "x86_64-pc-windows-msvc".to_string()
            } else if cfg!(target_os = "macos") {
                "x86_64-apple-darwin".to_string()
            } else {
                panic!("Unsupported OS, maybe try setting RA_TARGET")
            }
        }
    }
}

fn exe_suffix(target: &str) -> String {
    if target.contains("-windows-") {
        ".exe".into()
    } else {
        "".into()
    }
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        write_file(&self.path, &self.original_contents).unwrap();
    }
}
<commit_msg>feat: build releases with lto=true<commit_after>use std::{
    env,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let dist = project_root().join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag)?;
        }
        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel)?;
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str) -> Result<()> {
    let _d = pushd("./editors/code")?;
    let nightly = release_tag == "nightly";

    let mut patch = Patch::new("./package.json")?;

    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": false,"#, "")
        .replace(",\n                \"$generated-end\": false", "");

    if nightly {
        patch.replace(
            r#""displayName": "rust-analyzer""#,
            r#""displayName": "rust-analyzer (nightly)""#,
        );
    }
    if !nightly {
        patch.replace(r#""enableProposedApi": true,"#, r#""#);
    }
    patch.commit()?;

    cmd!("npm ci").run()?;
    cmd!("npx vsce package -o ../../dist/rust-analyzer.vsix").run()?;
    Ok(())
}

fn dist_server(release_channel: &str) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true");
    let target = get_target();
    if target.contains("-linux-gnu") || target.contains("-linux-musl") {
        env::set_var("CC", "clang");
    }

    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;

    let suffix = exe_suffix(&target);
    let src =
        Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix));
    let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix));
    gzip(&src, &dst.with_extension("gz"))?;

    // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
    // Remove this block after a couple of releases
    match target.as_ref() {
        "x86_64-unknown-linux-gnu" => {
            cp(&src, "dist/rust-analyzer-linux")?;
            gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
        }
        "x86_64-pc-windows-msvc" => {
            cp(&src, "dist/rust-analyzer-windows.exe")?;
            gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
        }
        "x86_64-apple-darwin" => {
            cp(&src, "dist/rust-analyzer-mac")?;
            gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
        }
        _ => {}
    }

    Ok(())
}

fn get_target() -> String {
    match env::var("RA_TARGET") {
        Ok(target) => target,
        _ => {
            if cfg!(target_os = "linux") {
                "x86_64-unknown-linux-gnu".to_string()
            } else if cfg!(target_os = "windows") {
                "x86_64-pc-windows-msvc".to_string()
            } else if cfg!(target_os = "macos") {
                "x86_64-apple-darwin".to_string()
            } else {
                panic!("Unsupported OS, maybe try setting RA_TARGET")
            }
        }
    }
}

fn exe_suffix(target: &str) -> String {
    if target.contains("-windows-") {
        ".exe".into()
    } else {
        "".into()
    }
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        write_file(&self.path, &self.original_contents).unwrap();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

use glium::Surface;

mod support;

#[test]
fn no_depth_buffer_depth_test() {
    let display = support::build_display();
    let (vertex_buffer, index_buffer, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::texture::Texture2d::empty_with_format(&display,
                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                            glium::texture::MipmapsOption::NoMipmap, 128, 128).unwrap();
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);

    let parameters = glium::DrawParameters {
        depth_test: glium::DepthTest::IfLess,
        .. Default::default()
    };

    match framebuffer.draw(&vertex_buffer, &index_buffer, &program,
                           &glium::uniforms::EmptyUniforms, &parameters)
    {
        Err(glium::DrawError::NoDepthBuffer) => (),
        a => panic!("{:?}", a)
    };

    display.assert_no_error(None);
}

#[test]
fn no_depth_buffer_depth_write() {
    let display = support::build_display();
    let (vertex_buffer, index_buffer, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::texture::Texture2d::empty_with_format(&display,
                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap, 128, 128).unwrap();
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);

    let parameters = glium::DrawParameters {
        depth_write: true,
        .. Default::default()
    };

    match framebuffer.draw(&vertex_buffer, &index_buffer, &program,
                           &glium::uniforms::EmptyUniforms, &parameters)
    {
        Err(glium::DrawError::NoDepthBuffer) => (),
        a => panic!("{:?}", a)
    };

    display.assert_no_error(None);
}

#[test]
fn simple_dimensions() {
    let display = support::build_display();

    let texture = glium::Texture2d::empty_with_format(&display,
                                              glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                              128, 128).unwrap();

    let framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    display.assert_no_error(None);
}

#[test]
fn simple_render_to_texture() {
    let display = support::build_display();
    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::Texture2d::empty_with_format(&display,
                                              glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                              128, 128).unwrap();

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms, &Default::default()).unwrap();

    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = texture.read();

    assert_eq!(read_back[0][0], (255, 0, 0, 255));
    assert_eq!(read_back[64][64], (255, 0, 0, 255));
    assert_eq!(read_back[127][127], (255, 0, 0, 255));

    display.assert_no_error(None);
}

#[test]
fn depth_texture2d() {
    use std::iter;

    let display = support::build_display();
    let (vb, ib) = support::build_rectangle_vb_ib(&display);

    // the program returns a Z coordinate between 0 (left of screen) and 1 (right of screen)
    let program = program!(&display,
        110 => {
            vertex: "
                #version 110

                attribute vec2 position;

                void main() {
                    gl_Position = vec4(position, position.x, 1.0);
                }
            ",
            fragment: "
                #version 110

                void main() {
                    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }
            ",
        },
        100 => {
            vertex: "
                #version 100

                attribute lowp vec2 position;

                void main() {
                    gl_Position = vec4(position, position.x, 1.0);
                }
            ",
            fragment: "
                #version 100

                void main() {
                    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }
            ",
        }).unwrap();

    // empty color attachment to put the data
    let color = glium::Texture2d::empty_with_format(&display,
                                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                            128, 128).unwrap();

    // depth texture with a value of 0.5 everywhere
    let depth_data = iter::repeat(iter::repeat(0.5f32).take(128).collect::<Vec<_>>())
                                  .take(128).collect::<Vec<_>>();
    let depth = match glium::texture::DepthTexture2d::new(&display, depth_data) {
        Err(_) => return,
        Ok(t) => t
    };

    // drawing with the `IfLess` depth test
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display,
                                                                                &color, &depth);
    let params = glium::DrawParameters {
        depth_test: glium::DepthTest::IfLess,
        .. Default::default()
    };

    framebuffer.clear_color(0.0, 0.0, 0.0, 1.0);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms, &params).unwrap();

    // reading back the color
    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = color.read();

    assert_eq!(read_back[0][0], (255, 255, 255, 255));
    assert_eq!(read_back[127][127], (0, 0, 0, 255));

    display.assert_no_error(None);
}

#[test]
fn multioutput() {
    let display = support::build_display();
    let (vb, ib) = support::build_rectangle_vb_ib(&display);

    let program = match glium::Program::from_source(&display,
        "
            #version 110

            attribute vec2 position;

            void main() {
                gl_Position = vec4(position, 0.0, 1.0);
            }
        ",
        "
            #version 330

            out vec4 color1;
            out vec4 color2;

            void main() {
                color1 = vec4(1.0, 1.0, 1.0, 1.0);
                color2 = vec4(1.0, 0.0, 0.0, 1.0);
            }
        ",
        None)
    {
        Err(glium::CompilationError(_)) => return,
        Ok(p) => p,
        e => e.unwrap()
    };

    // building two empty color attachments
    let color1 = glium::Texture2d::empty_with_format(&display,
                                               glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                               glium::texture::MipmapsOption::AutoGeneratedMipmaps,
                                               128, 128).unwrap();
    color1.as_surface().clear_color(0.0, 0.0, 0.0, 1.0);

    let color2 = glium::Texture2d::empty_with_format(&display,
                                               glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                               glium::texture::MipmapsOption::AutoGeneratedMipmaps,
                                               128, 128).unwrap();
    color2.as_surface().clear_color(0.0, 0.0, 0.0, 1.0);

    // building the framebuffer
    let mut framebuffer = glium::framebuffer::MultiOutputFrameBuffer::new(&display,
                                             &[("color1", &color1), ("color2", &color2)]);

    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // checking color1
    let read_back1: Vec<Vec<(u8, u8, u8, u8)>> = color1.read();
    for row in read_back1.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 255, 255, 255));
        }
    }

    // checking color2
    let read_back2: Vec<Vec<(u8, u8, u8, u8)>> = color2.read();
    for row in read_back2.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 0, 0, 255));
        }
    }

    display.assert_no_error(None);
}

#[test]
fn array_level() {
    let display = support::build_display();

    let texture = match glium::texture::Texture2dArray::empty(&display, 128, 128, 4) {
        Ok(t) => t,
        Err(_) => return
    };

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display,
                                                          texture.main_level().layer(2).unwrap());
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // TODO: read the texture to see if it succeeded

    display.assert_no_error(None);
}

#[test]
fn cubemap_layer() {
    // ignoring test on travis
    // TODO: find out why they are failing
    if ::std::env::var("TRAVIS").is_ok() {
        return;
    }

    let display = support::build_display();

    let texture = match glium::texture::Cubemap::empty(&display, 128) {
        Ok(t) => t,
        Err(_) => return
    };

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display,
                    texture.main_level().first_layer().image(glium::texture::CubeLayer::PositiveY));
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // TODO: read the texture to see if it succeeded

    display.assert_no_error(None);
}
<commit_msg>Add test case for framebuffers with too many color attachments<commit_after>#[macro_use]
extern crate glium;

use glium::Surface;

mod support;

#[test]
fn no_depth_buffer_depth_test() {
    let display = support::build_display();
    let (vertex_buffer, index_buffer, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::texture::Texture2d::empty_with_format(&display,
                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                            glium::texture::MipmapsOption::NoMipmap, 128, 128).unwrap();
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);

    let parameters = glium::DrawParameters {
        depth_test: glium::DepthTest::IfLess,
        .. Default::default()
    };

    match framebuffer.draw(&vertex_buffer, &index_buffer, &program,
                           &glium::uniforms::EmptyUniforms, &parameters)
    {
        Err(glium::DrawError::NoDepthBuffer) => (),
        a => panic!("{:?}", a)
    };

    display.assert_no_error(None);
}

#[test]
fn no_depth_buffer_depth_write() {
    let display = support::build_display();
    let (vertex_buffer, index_buffer, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::texture::Texture2d::empty_with_format(&display,
                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap, 128, 128).unwrap();
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);

    let parameters = glium::DrawParameters {
        depth_write: true,
        .. Default::default()
    };

    match framebuffer.draw(&vertex_buffer, &index_buffer, &program,
                           &glium::uniforms::EmptyUniforms, &parameters)
    {
        Err(glium::DrawError::NoDepthBuffer) => (),
        a => panic!("{:?}", a)
    };

    display.assert_no_error(None);
}

#[test]
fn simple_dimensions() {
    let display = support::build_display();

    let texture = glium::Texture2d::empty_with_format(&display,
                                              glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                              128, 128).unwrap();

    let framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    display.assert_no_error(None);
}

#[test]
fn simple_render_to_texture() {
    let display = support::build_display();
    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);

    let texture = glium::Texture2d::empty_with_format(&display,
                                              glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                              128, 128).unwrap();

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display, &texture);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms, &Default::default()).unwrap();

    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = texture.read();

    assert_eq!(read_back[0][0], (255, 0, 0, 255));
    assert_eq!(read_back[64][64], (255, 0, 0, 255));
    assert_eq!(read_back[127][127], (255, 0, 0, 255));

    display.assert_no_error(None);
}

#[test]
fn depth_texture2d() {
    use std::iter;

    let display = support::build_display();
    let (vb, ib) = support::build_rectangle_vb_ib(&display);

    // the program returns a Z coordinate between 0 (left of screen) and 1 (right of screen)
    let program = program!(&display,
        110 => {
            vertex: "
                #version 110

                attribute vec2 position;

                void main() {
                    gl_Position = vec4(position, position.x, 1.0);
                }
            ",
            fragment: "
                #version 110

                void main() {
                    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }
            ",
        },
        100 => {
            vertex: "
                #version 100

                attribute lowp vec2 position;

                void main() {
                    gl_Position = vec4(position, position.x, 1.0);
                }
            ",
            fragment: "
                #version 100

                void main() {
                    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }
            ",
        }).unwrap();

    // empty color attachment to put the data
    let color = glium::Texture2d::empty_with_format(&display,
                                            glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                            glium::texture::MipmapsOption::NoMipmap,
                                            128, 128).unwrap();

    // depth texture with a value of 0.5 everywhere
    let depth_data = iter::repeat(iter::repeat(0.5f32).take(128).collect::<Vec<_>>())
                                  .take(128).collect::<Vec<_>>();
    let depth = match glium::texture::DepthTexture2d::new(&display, depth_data) {
        Err(_) => return,
        Ok(t) => t
    };

    // drawing with the `IfLess` depth test
    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display,
                                                                                &color, &depth);
    let params = glium::DrawParameters {
        depth_test: glium::DepthTest::IfLess,
        .. Default::default()
    };

    framebuffer.clear_color(0.0, 0.0, 0.0, 1.0);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms, &params).unwrap();

    // reading back the color
    let read_back: Vec<Vec<(u8, u8, u8, u8)>> = color.read();

    assert_eq!(read_back[0][0], (255, 255, 255, 255));
    assert_eq!(read_back[127][127], (0, 0, 0, 255));

    display.assert_no_error(None);
}

#[test]
fn multioutput() {
    let display = support::build_display();
    let (vb, ib) = support::build_rectangle_vb_ib(&display);

    let program = match glium::Program::from_source(&display,
        "
            #version 110

            attribute vec2 position;

            void main() {
                gl_Position = vec4(position, 0.0, 1.0);
            }
        ",
        "
            #version 330

            out vec4 color1;
            out vec4 color2;

            void main() {
                color1 = vec4(1.0, 1.0, 1.0, 1.0);
                color2 = vec4(1.0, 0.0, 0.0, 1.0);
            }
        ",
        None)
    {
        Err(glium::CompilationError(_)) => return,
        Ok(p) => p,
        e => e.unwrap()
    };

    // building two empty color attachments
    let color1 = glium::Texture2d::empty_with_format(&display,
                                               glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                               glium::texture::MipmapsOption::AutoGeneratedMipmaps,
                                               128, 128).unwrap();
    color1.as_surface().clear_color(0.0, 0.0, 0.0, 1.0);

    let color2 = glium::Texture2d::empty_with_format(&display,
                                               glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                               glium::texture::MipmapsOption::AutoGeneratedMipmaps,
                                               128, 128).unwrap();
    color2.as_surface().clear_color(0.0, 0.0, 0.0, 1.0);

    // building the framebuffer
    let mut framebuffer = glium::framebuffer::MultiOutputFrameBuffer::new(&display,
                                             &[("color1", &color1), ("color2", &color2)]);

    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // checking color1
    let read_back1: Vec<Vec<(u8, u8, u8, u8)>> = color1.read();
    for row in read_back1.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 255, 255, 255));
        }
    }

    // checking color2
    let read_back2: Vec<Vec<(u8, u8, u8, u8)>> = color2.read();
    for row in read_back2.iter() {
        for pixel in row.iter() {
            assert_eq!(pixel, &(255, 0, 0, 255));
        }
    }

    display.assert_no_error(None);
}

#[test]
fn array_level() {
    let display = support::build_display();

    let texture = match glium::texture::Texture2dArray::empty(&display, 128, 128, 4) {
        Ok(t) => t,
        Err(_) => return
    };

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display,
                                                          texture.main_level().layer(2).unwrap());
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // TODO: read the texture to see if it succeeded

    display.assert_no_error(None);
}

#[test]
fn cubemap_layer() {
    // ignoring test on travis
    // TODO: find out why they are failing
    if ::std::env::var("TRAVIS").is_ok() {
        return;
    }

    let display = support::build_display();

    let texture = match glium::texture::Cubemap::empty(&display, 128) {
        Ok(t) => t,
        Err(_) => return
    };

    let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::new(&display,
                    texture.main_level().first_layer().image(glium::texture::CubeLayer::PositiveY));
    assert_eq!(framebuffer.get_dimensions(), (128, 128));

    let (vb, ib, program) = support::build_fullscreen_red_pipeline(&display);
    framebuffer.draw(&vb, &ib, &program, &glium::uniforms::EmptyUniforms,
                     &Default::default()).unwrap();

    // TODO: read the texture to see if it succeeded

    display.assert_no_error(None);
}

#[test]
#[should_panic]
fn multi_color_attachments_maximum() {
   let display = support::build_display();

   let color_textures = (0 .. 32)
        .map(|_| {
            glium::Texture2d::empty_with_format(&display,
                                               glium::texture::UncompressedFloatFormat::U8U8U8U8,
                                               glium::texture::MipmapsOption::NoMipmap,
                                               128, 128).unwrap()
        })
        .collect::<Vec<_>>();

   let colors = (0 .. color_textures.len()).map(|i| {("attachment", &color_textures[i])} ).collect::<Vec<_>>();

   let framebuffer = glium::framebuffer::MultiOutputFrameBuffer::new(&display, &colors[..]);
}<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::common::type_not_allowed;
use libra_types::transaction::{ArgumentABI, ScriptABI, TypeArgumentABI};
use move_core_types::language_storage::TypeTag;

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

/// Output a header-only library providing C++ transaction builders for the given ABIs.
pub fn output(out: &mut dyn Write, abis: &[ScriptABI], namespace: Option<&str>) -> Result<()> {
    output_preamble(out)?;
    output_open_namespace(out, namespace)?;
    output_using_namespaces(out)?;
    for abi in abis {
        output_builder_definition(out, abi, /* inlined */ true)?;
    }
    output_close_namespace(out, namespace)
}

/// Output the headers of a library providing C++ transaction builders for the given ABIs.
pub fn output_library_header(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    namespace: Option<&str>,
) -> Result<()> {
    output_preamble(out)?;
    output_open_namespace(out, namespace)?;
    output_using_namespaces(out)?;
    for abi in abis {
        output_builder_declaration(out, abi)?;
    }
    output_close_namespace(out, namespace)
}

/// Output the function definitions of a library providing C++ transaction builders for the given ABIs.
pub fn output_library_body(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    library_name: &str,
    namespace: Option<&str>,
) -> Result<()> {
    writeln!(out, "#include \"{}.hpp\"\n", library_name)?;
    output_open_namespace(out, namespace)?;
    output_using_namespaces(out)?;
    for abi in abis {
        output_builder_definition(out, abi, /* inlined */ false)?;
    }
    output_close_namespace(out, namespace)
}

fn output_preamble(out: &mut dyn Write) -> Result<()> {
    writeln!(
        out,
        r#"
#pragma once

#include "libra_types.hpp"
"#
    )
}

fn output_using_namespaces(out: &mut dyn Write) -> Result<()> {
    writeln!(
        out,
        r#"
using namespace serde;
using namespace libra_types;
"#
    )
}

fn output_open_namespace(out: &mut dyn std::io::Write, namespace: Option<&str>) -> Result<()> {
    if let Some(name) = namespace {
        writeln!(out, "namespace {} {{\n", name,)?;
    }
    Ok(())
}

fn output_close_namespace(out: &mut dyn std::io::Write, namespace: Option<&str>) -> Result<()> {
    if let Some(name) = namespace {
        writeln!(out, "\n}} // end of namespace {}", name,)?;
    }
    Ok(())
}

fn output_builder_declaration(out: &mut dyn Write, abi: &ScriptABI) -> Result<()> {
    write!(out, "\n{}", quote_doc(abi.doc()))?;
    writeln!(
        out,
        "Script encode_{}_script({});",
        abi.name(),
        [
            quote_type_parameters(abi.ty_args()),
            quote_parameters(abi.args()),
        ]
        .concat()
        .join(", ")
    )?;
    Ok(())
}

fn output_builder_definition(out: &mut dyn Write, abi: &ScriptABI, inlined: bool) -> Result<()> {
    if inlined {
        write!(out, "\n{}", quote_doc(abi.doc()))?;
    }
    writeln!(
        out,
        "{}Script encode_{}_script({}) {{",
        if inlined { "inline " } else { "" },
        abi.name(),
        [
            quote_type_parameters(abi.ty_args()),
            quote_parameters(abi.args()),
        ]
        .concat()
        .join(", ")
    )?;
    writeln!(
        out,
        r#"    return Script {{
        {},
        std::vector<TypeTag> {{{}}},
        std::vector<TransactionArgument> {{{}}},
    }};"#,
        quote_code(abi.code()),
        quote_type_arguments(abi.ty_args()),
        quote_arguments(abi.args()),
    )?;
    writeln!(out, "}}")?;
    Ok(())
}

fn quote_doc(doc: &str) -> String {
    let doc = crate::common::prepare_doc_string(doc);
    textwrap::indent(&doc, "/// ")
}

fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec<String> {
    ty_args
        .iter()
        .map(|ty_arg| format!("TypeTag {}", ty_arg.name()))
        .collect()
}

fn quote_parameters(args: &[ArgumentABI]) -> Vec<String> {
    args.iter()
        .map(|arg| format!("{} {}", quote_type(arg.type_tag()), arg.name()))
        .collect()
}

fn quote_code(code: &[u8]) -> String {
    format!(
        "std::vector<uint8_t> {{{}}}",
        code.iter()
            .map(|x| format!("{}", x))
            .collect::<Vec<_>>()
            .join(", ")
    )
}

fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String {
    ty_args
        .iter()
        .map(|ty_arg| format!("std::move({})", ty_arg.name()))
        .collect::<Vec<_>>()
        .join(", ")
}

fn quote_arguments(args: &[ArgumentABI]) -> String {
    args.iter()
        .map(|arg| quote_transaction_argument(arg.type_tag(), arg.name()))
        .collect::<Vec<_>>()
        .join(", ")
}

fn quote_type(type_tag: &TypeTag) -> String {
    use TypeTag::*;
    match type_tag {
        Bool => "bool".into(),
        U8 => "uint8_t".into(),
        U64 => "uint64_t".into(),
        U128 => "uint128_t".into(),
        Address => "AccountAddress".into(),
        Vector(type_tag) => match type_tag.as_ref() {
            U8 => "std::vector<uint8_t>".into(),
            _ => type_not_allowed(type_tag),
        },
        Struct(_) | Signer => type_not_allowed(type_tag),
    }
}

fn quote_transaction_argument(type_tag: &TypeTag, name: &str) -> String {
    use TypeTag::*;
    match type_tag {
        Bool => format!("{{TransactionArgument::Bool {{{}}} }}", name),
        U8 => format!("{{TransactionArgument::U8 {{{}}} }}", name),
        U64 => format!("{{TransactionArgument::U64 {{{}}} }}", name),
        U128 => format!("{{TransactionArgument::U128 {{{}}} }}", name),
        // Adding std::move in the non-obvious cases to be future-proof.
        Address => format!("{{TransactionArgument::Address {{std::move({})}}}}", name),
        Vector(type_tag) => match type_tag.as_ref() {
            U8 => format!("{{TransactionArgument::U8Vector {{std::move({})}}}}", name),
            _ => type_not_allowed(type_tag),
        },

        Struct(_) | Signer => type_not_allowed(type_tag),
    }
}

pub struct Installer {
    install_dir: PathBuf,
}

impl Installer {
    pub fn new(install_dir: PathBuf) -> Self {
        Installer { install_dir }
    }
}

impl crate::SourceInstaller for Installer {
    type Error = Box<dyn std::error::Error>;

    fn install_transaction_builders(
        &self,
        name: &str,
        abis: &[ScriptABI],
    ) -> std::result::Result<(), Self::Error> {
        let dir_path = &self.install_dir;
        std::fs::create_dir_all(dir_path)?;
        let header_path = dir_path.join(name.to_string() + ".hpp");
        let mut header = std::fs::File::create(&header_path)?;
        output_library_header(&mut header, abis, Some(name))?;
        let body_path = dir_path.join(name.to_string() + ".cpp");
        let mut body = std::fs::File::create(&body_path)?;
        output_library_body(&mut body, abis, name, Some(name))?;
        Ok(())
    }
}
<commit_msg>[transaction builder generator] c++: create CppEmitter<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::common::type_not_allowed;
use libra_types::transaction::{ArgumentABI, ScriptABI, TypeArgumentABI};
use move_core_types::language_storage::TypeTag;
use serde_generate::indent::{IndentConfig, IndentedWriter};

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

/// Output a header-only library providing C++ transaction builders for the given ABIs.
pub fn output(out: &mut dyn Write, abis: &[ScriptABI], namespace: Option<&str>) -> Result<()> {
    let mut emitter = CppEmitter {
        out: IndentedWriter::new(out, IndentConfig::Space(4)),
        namespace,
        inlined_definitions: true,
    };
    emitter.output_preamble()?;
    emitter.output_open_namespace()?;
    emitter.output_using_namespaces()?;
    for abi in abis {
        emitter.output_builder_definition(abi)?;
    }
    emitter.output_close_namespace()
}

/// Output the headers of a library providing C++ transaction builders for the given ABIs.
pub fn output_library_header(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    namespace: Option<&str>,
) -> Result<()> {
    let mut emitter = CppEmitter {
        out: IndentedWriter::new(out, IndentConfig::Space(4)),
        namespace,
        inlined_definitions: true,
    };
    emitter.output_preamble()?;
    emitter.output_open_namespace()?;
    emitter.output_using_namespaces()?;
    for abi in abis {
        emitter.output_builder_declaration(abi)?;
    }
    emitter.output_close_namespace()
}

/// Output the function definitions of a library providing C++ transaction builders for the given ABIs.
pub fn output_library_body(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    library_name: &str,
    namespace: Option<&str>,
) -> Result<()> {
    let mut emitter = CppEmitter {
        out: IndentedWriter::new(out, IndentConfig::Space(4)),
        namespace,
        inlined_definitions: false,
    };
    writeln!(emitter.out, "#include \"{}.hpp\"\n", library_name)?;
    emitter.output_open_namespace()?;
    emitter.output_using_namespaces()?;
    for abi in abis {
        emitter.output_builder_definition(abi)?;
    }
    emitter.output_close_namespace()
}

/// Shared state for the Cpp code generator.
struct CppEmitter<'a, T> {
    /// Writer.
    out: IndentedWriter<T>,
    /// Name of the package owning the generated definitions (e.g. "com.facebook.my_package")
    namespace: Option<&'a str>,
    /// Whether function definitions should be prefixed with "inlined"
    inlined_definitions: bool,
}

impl<'a, T> CppEmitter<'a, T>
where
    T: Write,
{
    fn output_preamble(&mut self) -> Result<()> {
        writeln!(
            self.out,
            r#"
#pragma once

#include "libra_types.hpp"
"#
        )
    }

    fn output_using_namespaces(&mut self) -> Result<()> {
        writeln!(
            self.out,
            r#"
using namespace serde;
using namespace libra_types;
"#
        )
    }

    fn output_open_namespace(&mut self) -> Result<()> {
        if let Some(name) = self.namespace {
            writeln!(self.out, "namespace {} {{\n", name)?;
        }
        Ok(())
    }

    fn output_close_namespace(&mut self) -> Result<()> {
        if let Some(name) = self.namespace {
            writeln!(self.out, "\n}} // end of namespace {}", name)?;
        }
        Ok(())
    }

    fn output_builder_declaration(&mut self, abi: &ScriptABI) -> Result<()> {
        write!(self.out, "\n{}", Self::quote_doc(abi.doc()))?;
        writeln!(
            self.out,
            "Script encode_{}_script({});",
            abi.name(),
            [
                Self::quote_type_parameters(abi.ty_args()),
                Self::quote_parameters(abi.args()),
            ]
            .concat()
            .join(", ")
        )?;
        Ok(())
    }

    fn output_builder_definition(&mut self, abi: &ScriptABI) -> Result<()> {
        if self.inlined_definitions {
            write!(self.out, "\n{}", Self::quote_doc(abi.doc()))?;
        }
        writeln!(
            self.out,
            "{}Script encode_{}_script({}) {{",
            if self.inlined_definitions {
                "inline "
            } else {
                ""
            },
            abi.name(),
            [
                Self::quote_type_parameters(abi.ty_args()),
                Self::quote_parameters(abi.args()),
            ]
            .concat()
            .join(", ")
        )?;
        writeln!(
            self.out,
            r#"    return Script {{
        {},
        std::vector<TypeTag> {{{}}},
        std::vector<TransactionArgument> {{{}}},
    }};"#,
            Self::quote_code(abi.code()),
            Self::quote_type_arguments(abi.ty_args()),
            Self::quote_arguments(abi.args()),
        )?;
        writeln!(self.out, "}}")?;
        Ok(())
    }

    fn quote_doc(doc: &str) -> String {
        let doc = crate::common::prepare_doc_string(doc);
        textwrap::indent(&doc, "/// ")
    }

    fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec<String> {
        ty_args
            .iter()
            .map(|ty_arg| format!("TypeTag {}", ty_arg.name()))
            .collect()
    }

    fn quote_parameters(args: &[ArgumentABI]) -> Vec<String> {
        args.iter()
            .map(|arg| format!("{} {}", Self::quote_type(arg.type_tag()), arg.name()))
            .collect()
    }

    fn quote_code(code: &[u8]) -> String {
        format!(
            "std::vector<uint8_t> {{{}}}",
            code.iter()
                .map(|x| format!("{}", x))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }

    fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String {
        ty_args
            .iter()
            .map(|ty_arg| format!("std::move({})", ty_arg.name()))
            .collect::<Vec<_>>()
            .join(", ")
    }

    fn quote_arguments(args: &[ArgumentABI]) -> String {
        args.iter()
            .map(|arg| Self::quote_transaction_argument(arg.type_tag(), arg.name()))
            .collect::<Vec<_>>()
            .join(", ")
    }

    fn quote_type(type_tag: &TypeTag) -> String {
        use TypeTag::*;
        match type_tag {
            Bool => "bool".into(),
            U8 => "uint8_t".into(),
            U64 => "uint64_t".into(),
            U128 => "uint128_t".into(),
            Address => "AccountAddress".into(),
            Vector(type_tag) => match type_tag.as_ref() {
                U8 => "std::vector<uint8_t>".into(),
                _ => type_not_allowed(type_tag),
            },
            Struct(_) | Signer => type_not_allowed(type_tag),
        }
    }

    fn quote_transaction_argument(type_tag: &TypeTag, name: &str) -> String {
        use TypeTag::*;
        match type_tag {
            Bool => format!("{{TransactionArgument::Bool {{{}}} }}", name),
            U8 => format!("{{TransactionArgument::U8 {{{}}} }}", name),
            U64 => format!("{{TransactionArgument::U64 {{{}}} }}", name),
            U128 => format!("{{TransactionArgument::U128 {{{}}} }}", name),
            // Adding std::move in the non-obvious cases to be future-proof.
            Address => format!("{{TransactionArgument::Address {{std::move({})}}}}", name),
            Vector(type_tag) => match type_tag.as_ref() {
                U8 => format!("{{TransactionArgument::U8Vector {{std::move({})}}}}", name),
                _ => type_not_allowed(type_tag),
            },

            Struct(_) | Signer => type_not_allowed(type_tag),
        }
    }
}

pub struct Installer {
    install_dir: PathBuf,
}

impl Installer {
    pub fn new(install_dir: PathBuf) -> Self {
        Installer { install_dir }
    }
}

impl crate::SourceInstaller for Installer {
    type Error = Box<dyn std::error::Error>;

    fn install_transaction_builders(
        &self,
        name: &str,
        abis: &[ScriptABI],
    ) -> std::result::Result<(), Self::Error> {
        let dir_path = &self.install_dir;
        std::fs::create_dir_all(dir_path)?;
        let header_path = dir_path.join(name.to_string() + ".hpp");
        let mut header = std::fs::File::create(&header_path)?;
        output_library_header(&mut header, abis, Some(name))?;
        let body_path = dir_path.join(name.to_string() + ".cpp");
        let mut body = std::fs::File::create(&body_path)?;
        output_library_body(&mut body, abis, name, Some(name))?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://rust-random.github.io/rand/")]

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]

#![allow(clippy::excessive_precision, clippy::float_cmp)]

//! Generating random samples from probability distributions.
//!
//! ## Re-exports
//!
//! This crate is a super-set of the [`rand::distributions`] module. See the
//! [`rand::distributions`] module documentation for an overview of the core
//! [`Distribution`] trait and implementations.
//!
//! The following are re-exported:
//!
//! - The [`Distribution`] trait and [`DistIter`] helper type
//! - The [`Standard`], [`Alphanumeric`], [`Uniform`], [`OpenClosed01`], [`Open01`] and [`Bernoulli`] distributions
//! - The [`weighted`] sub-module
//!
//! ## Distributions
//!
//! This crate provides the following probability distributions:
//!
//! - Related to real-valued quantities that grow linearly
//!   (e.g. errors, offsets):
//!   - [`Normal`] distribution, and [`StandardNormal`] as a primitive
//!   - [`Cauchy`] distribution
//! - Related to Bernoulli trials (yes/no events, with a given probability):
//!   - [`Binomial`] distribution
//! - Related to positive real-valued quantities that grow exponentially
//!   (e.g. prices, incomes, populations):
//!   - [`LogNormal`] distribution
//! - Related to the occurrence of independent events at a given rate:
//!   - [`Pareto`] distribution
//!   - [`Poisson`] distribution
//!   - [`Exp`]onential distribution, and [`Exp1`] as a primitive
//!   - [`Weibull`] distribution
//! - Gamma and derived distributions:
//!   - [`Gamma`] distribution
//!   - [`ChiSquared`] distribution
//!   - [`StudentT`] distribution
//!   - [`FisherF`] distribution
//! - Triangular distribution:
//!   - [`Beta`] distribution
//!   - [`Triangular`] distribution
//! - Multivariate probability distributions
//!   - [`Dirichlet`] distribution
//!   - [`UnitSphere`] distribution
//!   - [`UnitBall`] distribution
//!   - [`UnitCircle`] distribution
//!   - [`UnitDisc`] distribution

pub use rand::distributions::{Distribution, DistIter, Standard,
    Alphanumeric, Uniform, OpenClosed01, Open01, Bernoulli, uniform, weighted};

pub use self::unit_sphere::UnitSphere;
pub use self::unit_ball::UnitBall;
pub use self::unit_circle::UnitCircle;
pub use self::unit_disc::UnitDisc;
pub use self::gamma::{Gamma, Error as GammaError, ChiSquared, ChiSquaredError,
    FisherF, FisherFError, StudentT, Beta, BetaError};
pub use self::normal::{Normal, Error as NormalError, LogNormal, StandardNormal};
pub use self::exponential::{Exp, Error as ExpError, Exp1};
pub use self::pareto::{Pareto, Error as ParetoError};
pub use self::pert::{Pert, PertError};
pub use self::poisson::{Poisson, Error as PoissonError};
pub use self::binomial::{Binomial, Error as BinomialError};
pub use self::cauchy::{Cauchy, Error as CauchyError};
pub use self::dirichlet::{Dirichlet, Error as DirichletError};
pub use self::triangular::{Triangular, TriangularError};
pub use self::weibull::{Weibull, Error as WeibullError};
pub use self::utils::Float;

mod unit_sphere;
mod unit_ball;
mod unit_circle;
mod unit_disc;
mod gamma;
mod normal;
mod exponential;
mod pareto;
mod pert;
mod poisson;
mod binomial;
mod cauchy;
mod dirichlet;
mod triangular;
mod weibull;
mod utils;
mod ziggurat_tables;

#[cfg(test)]
mod test {
    // Notes on testing
    //
    // Testing random number distributions correctly is hard. The following
    // testing is desired:
    //
    // - Construction: test initialisation with a few valid parameter sets.
    // - Erroneous usage: test that incorrect usage generates an error.
    // - Vector: test that usage with fixed inputs (including RNG) generates a
    //   fixed output sequence on all platforms.
    // - Correctness at fixed points (optional): using a specific mock RNG,
    //   check that specific values are sampled (e.g. end-points and median of
    //   distribution).
    // - Correctness of PDF (extra): generate a histogram of samples within a
    //   certain range, and check this approximates the PDF. These tests are
    //   expected to be expensive, and should be behind a feature-gate.
    //
    // TODO: Vector and correctness tests are largely absent so far.
    // NOTE: Some distributions have tests checking only that samples can be
    // generated. This is redundant with vector and correctness tests.

    /// Construct a deterministic RNG with the given seed
    pub fn rng(seed: u64) -> impl rand::RngCore {
        // For tests, we want a statistically good, fast, reproducible RNG.
        // PCG32 will do fine, and will be easy to embed if we ever need to.
        const INC: u64 = 11634580027462260723;
        rand_pcg::Pcg32::new(seed, INC)
    }
}
<commit_msg>rand_distr: Disable some more noisy lints<commit_after>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://rust-random.github.io/rand/")]

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]

#![allow(clippy::excessive_precision, clippy::float_cmp, clippy::unreadable_literal)]
#![allow(clippy::neg_cmp_op_on_partial_ord)]  // suggested fix too verbose

//! Generating random samples from probability distributions.
//!
//! ## Re-exports
//!
//! This crate is a super-set of the [`rand::distributions`] module. See the
//! [`rand::distributions`] module documentation for an overview of the core
//! [`Distribution`] trait and implementations.
//!
//! The following are re-exported:
//!
//! - The [`Distribution`] trait and [`DistIter`] helper type
//! - The [`Standard`], [`Alphanumeric`], [`Uniform`], [`OpenClosed01`], [`Open01`] and [`Bernoulli`] distributions
//! - The [`weighted`] sub-module
//!
//! ## Distributions
//!
//! This crate provides the following probability distributions:
//!
//! - Related to real-valued quantities that grow linearly
//!   (e.g. errors, offsets):
//!   - [`Normal`] distribution, and [`StandardNormal`] as a primitive
//!   - [`Cauchy`] distribution
//! - Related to Bernoulli trials (yes/no events, with a given probability):
//!   - [`Binomial`] distribution
//! - Related to positive real-valued quantities that grow exponentially
//!   (e.g. prices, incomes, populations):
//!   - [`LogNormal`] distribution
//! - Related to the occurrence of independent events at a given rate:
//!   - [`Pareto`] distribution
//!   - [`Poisson`] distribution
//!   - [`Exp`]onential distribution, and [`Exp1`] as a primitive
//!   - [`Weibull`] distribution
//! - Gamma and derived distributions:
//!   - [`Gamma`] distribution
//!   - [`ChiSquared`] distribution
//!   - [`StudentT`] distribution
//!   - [`FisherF`] distribution
//! - Triangular distribution:
//!   - [`Beta`] distribution
//!   - [`Triangular`] distribution
//! - Multivariate probability distributions
//!   - [`Dirichlet`] distribution
//!   - [`UnitSphere`] distribution
//!   - [`UnitBall`] distribution
//!   - [`UnitCircle`] distribution
//!   - [`UnitDisc`] distribution

pub use rand::distributions::{Distribution, DistIter, Standard,
    Alphanumeric, Uniform, OpenClosed01, Open01, Bernoulli, uniform, weighted};

pub use self::unit_sphere::UnitSphere;
pub use self::unit_ball::UnitBall;
pub use self::unit_circle::UnitCircle;
pub use self::unit_disc::UnitDisc;
pub use self::gamma::{Gamma, Error as GammaError, ChiSquared, ChiSquaredError,
    FisherF, FisherFError, StudentT, Beta, BetaError};
pub use self::normal::{Normal, Error as NormalError, LogNormal, StandardNormal};
pub use self::exponential::{Exp, Error as ExpError, Exp1};
pub use self::pareto::{Pareto, Error as ParetoError};
pub use self::pert::{Pert, PertError};
pub use self::poisson::{Poisson, Error as PoissonError};
pub use self::binomial::{Binomial, Error as BinomialError};
pub use self::cauchy::{Cauchy, Error as CauchyError};
pub use self::dirichlet::{Dirichlet, Error as DirichletError};
pub use self::triangular::{Triangular, TriangularError};
pub use self::weibull::{Weibull, Error as WeibullError};
pub use self::utils::Float;

mod unit_sphere;
mod unit_ball;
mod unit_circle;
mod unit_disc;
mod gamma;
mod normal;
mod exponential;
mod pareto;
mod pert;
mod poisson;
mod binomial;
mod cauchy;
mod dirichlet;
mod triangular;
mod weibull;
mod utils;
mod ziggurat_tables;

#[cfg(test)]
mod test {
    // Notes on testing
    //
    // Testing random number distributions correctly is hard. The following
    // testing is desired:
    //
    // - Construction: test initialisation with a few valid parameter sets.
    // - Erroneous usage: test that incorrect usage generates an error.
    // - Vector: test that usage with fixed inputs (including RNG) generates a
    //   fixed output sequence on all platforms.
    // - Correctness at fixed points (optional): using a specific mock RNG,
    //   check that specific values are sampled (e.g. end-points and median of
    //   distribution).
    // - Correctness of PDF (extra): generate a histogram of samples within a
    //   certain range, and check this approximates the PDF. These tests are
    //   expected to be expensive, and should be behind a feature-gate.
    //
    // TODO: Vector and correctness tests are largely absent so far.
    // NOTE: Some distributions have tests checking only that samples can be
    // generated. This is redundant with vector and correctness tests.

    /// Construct a deterministic RNG with the given seed
    pub fn rng(seed: u64) -> impl rand::RngCore {
        // For tests, we want a statistically good, fast, reproducible RNG.
        // PCG32 will do fine, and will be easy to embed if we ever need to.
        const INC: u64 = 11634580027462260723;
        rand_pcg::Pcg32::new(seed, INC)
    }
}
<|endoftext|>


<commit_before>//! Asynchronous DNS resolver
#![macro_use]

pub use self::resolver::{DnsResolve, DnsResolver};

mod resolver;
#[cfg(feature = "trust-dns")]
mod trust_dns_resolver;

/// Helper macro for resolving host and then process each addresses
#[macro_export]
macro_rules! lookup_then {
    ($context:expr, $addr:expr, $port:expr, |$resolved_addr:ident| $body:block) => {{
        let mut result = None;

        for $resolved_addr in $context.dns_resolve($addr, $port).await? {
            match $body {
                Ok(r) => {
                    result = Some(Ok(($resolved_addr, r)));
                    break;
                }
                Err(err) => {
                    result = Some(Err(err));
                }
            }
        }

        result.expect("resolved empty address")
    }};
}

#[macro_export]
macro_rules! lookup_then_connect {
    ($context:expr, $addr:expr, $port:expr, |$resolved_addr:ident| $body:block) => {{
        use futures::future::{self, Either};
        use log::trace;
        use std::{net::SocketAddr, time::Duration};
        use tokio::time;

        let ipv6_first = $context.ipv6_first();

        let mut v4_addrs = Vec::new();
        let mut v6_addrs = Vec::new();

        for addr in $context.dns_resolve($addr, $port).await? {
            match addr {
                SocketAddr::V4(..) => v4_addrs.push(addr),
                SocketAddr::V6(..) => v6_addrs.push(addr),
            }
        }

        let has_v4 = !v4_addrs.is_empty();
        let has_v6 = !v6_addrs.is_empty();

        assert!(has_v4 || has_v6, "resolved empty address");

        // Happy Eyeballs, RFC6555, RFC8305
        const FIXED_DELAY: Duration = Duration::from_millis(200);

        // Connects every addresses synchronously.
        // TODO: Try another address after FIXED_DELAY if one of the IPs is unreachable.
        //
        // This would require `future::select_ok`, which will require futures to be `Unpin`
        // (boxed future, excessive memory allocation).

        let connect_v4 = async {
            // use futures::FutureExt;
            //
            // let mut vfut = Vec::new();
            //
            // let mut delay = Duration::from_millis(0);
            //
            // for $resolved_addr in v4_addrs {
            //     vfut.push(
            //         async move {
            //             if delay != Duration::from_millis(0) {
            //                 time::sleep(delay).await;
            //             }
            //
            //             trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);
            //
            //             match $body {
            //                 Ok(r) => Ok(($resolved_addr, r)),
            //                 Err(err) => Err(err),
            //             }
            //         }
            //         .boxed(),
            //     );
            //
            //     delay += FIXED_DELAY;
            // }
            //
            // match future::select_ok(vfut).await {
            //     Ok((r, _)) => Ok(r),
            //     Err(err) => Err(err),
            // }

            let mut result = None;

            for $resolved_addr in v4_addrs {
                trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);

                match $body {
                    Ok(r) => {
                        trace!("connected {}:{} {}", $addr, $port, $resolved_addr);
                        result = Some(Ok(($resolved_addr, r)));
                        break;
                    }
                    Err(err) => {
                        result = Some(Err(err));
                    }
                }
            }

            result.expect("impossible")
        };

        let connect_v6 = async {
            let mut result = None;

            for $resolved_addr in v6_addrs {
                trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);

                match $body {
                    Ok(r) => {
                        trace!("connected {}:{} {}", $addr, $port, $resolved_addr);
                        result = Some(Ok(($resolved_addr, r)));
                        break;
                    }
                    Err(err) => {
                        result = Some(Err(err));
                    }
                }
            }

            result.expect("impossible")
        };

        if has_v4 && !has_v6 {
            connect_v4.await
        } else if !has_v4 && has_v6 {
            connect_v6.await
        } else {
            if ipv6_first {
                let v4_fut = async move {
                    time::sleep(FIXED_DELAY).await;
                    connect_v4.await
                };
                let v6_fut = connect_v6;

                tokio::pin!(v4_fut);
                tokio::pin!(v6_fut);

                match future::select(v4_fut, v6_fut).await {
                    Either::Left((v4_res, v6_fut)) => match v4_res {
                        Ok(res) => Ok(res),
                        Err(_v4_err) => v6_fut.await,
                    },
                    Either::Right((v6_res, v4_fut)) => match v6_res {
                        Ok(res) => Ok(res),
                        Err(_v6_err) => v4_fut.await,
                    },
                }
            } else {
                let v6_fut = async move {
                    time::sleep(FIXED_DELAY).await;
                    connect_v6.await
                };
                let v4_fut = connect_v4;

                tokio::pin!(v4_fut);
                tokio::pin!(v6_fut);

                match future::select(v4_fut, v6_fut).await {
                    Either::Left((v4_res, v6_fut)) => match v4_res {
                        Ok(res) => Ok(res),
                        Err(_v4_err) => v6_fut.await,
                    },
                    Either::Right((v6_res, v4_fut)) => match v6_res {
                        Ok(res) => Ok(res),
                        Err(_v6_err) => v4_fut.await,
                    },
                }
            }
        }
    }};
}
<commit_msg>Happy Eyeballs follows RFC6555 300ms<commit_after>//! Asynchronous DNS resolver
#![macro_use]

pub use self::resolver::{DnsResolve, DnsResolver};

mod resolver;
#[cfg(feature = "trust-dns")]
mod trust_dns_resolver;

/// Helper macro for resolving host and then process each addresses
#[macro_export]
macro_rules! lookup_then {
    ($context:expr, $addr:expr, $port:expr, |$resolved_addr:ident| $body:block) => {{
        let mut result = None;

        for $resolved_addr in $context.dns_resolve($addr, $port).await? {
            match $body {
                Ok(r) => {
                    result = Some(Ok(($resolved_addr, r)));
                    break;
                }
                Err(err) => {
                    result = Some(Err(err));
                }
            }
        }

        result.expect("resolved empty address")
    }};
}

#[macro_export]
macro_rules! lookup_then_connect {
    ($context:expr, $addr:expr, $port:expr, |$resolved_addr:ident| $body:block) => {{
        use futures::future::{self, Either};
        use log::trace;
        use std::{net::SocketAddr, time::Duration};
        use tokio::time;

        let ipv6_first = $context.ipv6_first();

        let mut v4_addrs = Vec::new();
        let mut v6_addrs = Vec::new();

        for addr in $context.dns_resolve($addr, $port).await? {
            match addr {
                SocketAddr::V4(..) => v4_addrs.push(addr),
                SocketAddr::V6(..) => v6_addrs.push(addr),
            }
        }

        let has_v4 = !v4_addrs.is_empty();
        let has_v6 = !v6_addrs.is_empty();

        assert!(has_v4 || has_v6, "resolved empty address");

        // Happy Eyeballs, RFC6555, RFC8305
        //
        // RFC6555 gives an example that Chrome and Firefox uses 300ms
        const FIXED_DELAY: Duration = Duration::from_millis(300);

        // Connects every addresses synchronously.
        // TODO: Try another address after FIXED_DELAY if one of the IPs is unreachable.
        //
        // This would require `future::select_ok`, which will require futures to be `Unpin`
        // (boxed future, excessive memory allocation).

        let connect_v4 = async {
            // use futures::FutureExt;
            //
            // let mut vfut = Vec::new();
            //
            // let mut delay = Duration::from_millis(0);
            //
            // for $resolved_addr in v4_addrs {
            //     vfut.push(
            //         async move {
            //             if delay != Duration::from_millis(0) {
            //                 time::sleep(delay).await;
            //             }
            //
            //             trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);
            //
            //             match $body {
            //                 Ok(r) => Ok(($resolved_addr, r)),
            //                 Err(err) => Err(err),
            //             }
            //         }
            //         .boxed(),
            //     );
            //
            //     delay += FIXED_DELAY;
            // }
            //
            // match future::select_ok(vfut).await {
            //     Ok((r, _)) => Ok(r),
            //     Err(err) => Err(err),
            // }

            let mut result = None;

            for $resolved_addr in v4_addrs {
                trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);

                match $body {
                    Ok(r) => {
                        trace!("connected {}:{} {}", $addr, $port, $resolved_addr);
                        result = Some(Ok(($resolved_addr, r)));
                        break;
                    }
                    Err(err) => {
                        result = Some(Err(err));
                    }
                }
            }

            result.expect("impossible")
        };

        let connect_v6 = async {
            let mut result = None;

            for $resolved_addr in v6_addrs {
                trace!("trying connect {}:{} {}", $addr, $port, $resolved_addr);

                match $body {
                    Ok(r) => {
                        trace!("connected {}:{} {}", $addr, $port, $resolved_addr);
                        result = Some(Ok(($resolved_addr, r)));
                        break;
                    }
                    Err(err) => {
                        result = Some(Err(err));
                    }
                }
            }

            result.expect("impossible")
        };

        if has_v4 && !has_v6 {
            connect_v4.await
        } else if !has_v4 && has_v6 {
            connect_v6.await
        } else {
            if ipv6_first {
                let v4_fut = async move {
                    time::sleep(FIXED_DELAY).await;
                    connect_v4.await
                };
                let v6_fut = connect_v6;

                tokio::pin!(v4_fut);
                tokio::pin!(v6_fut);

                match future::select(v4_fut, v6_fut).await {
                    Either::Left((v4_res, v6_fut)) => match v4_res {
                        Ok(res) => Ok(res),
                        Err(_v4_err) => v6_fut.await,
                    },
                    Either::Right((v6_res, v4_fut)) => match v6_res {
                        Ok(res) => Ok(res),
                        Err(_v6_err) => v4_fut.await,
                    },
                }
            } else {
                let v6_fut = async move {
                    time::sleep(FIXED_DELAY).await;
                    connect_v6.await
                };
                let v4_fut = connect_v4;

                tokio::pin!(v4_fut);
                tokio::pin!(v6_fut);

                match future::select(v4_fut, v6_fut).await {
                    Either::Left((v4_res, v6_fut)) => match v4_res {
                        Ok(res) => Ok(res),
                        Err(_v4_err) => v6_fut.await,
                    },
                    Either::Right((v6_res, v4_fut)) => match v6_res {
                        Ok(res) => Ok(res),
                        Err(_v6_err) => v4_fut.await,
                    },
                }
            }
        }
    }};
}
<|endoftext|>