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

use super::CreateEmbed;
#[cfg(feature = "unstable_discord_api")]
use crate::builder::CreateComponents;
use crate::internal::prelude::*;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| {
///     m.content("hello")
/// })
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    fn _add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(Vec::new()));
        let embeds_array = embeds.as_array_mut().expect("Embeds must be an array");

        embeds_array.push(embed);

        self
    }

    /// Add an embed for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embed()`] to replace existing
    /// embeds.
    pub fn add_embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self._add_embed(embed)
    }

    /// Add multiple embeds for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embeds()`] to replace existing
    /// embeds.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::set_embed()`].
    ///
    /// **Note**: This will replace all existing embeds. Use
    /// [`Self::add_embed()`] to add an additional embed.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::embed()`].
    ///
    /// **Note**: This will replace all existing embeds.
    /// Use [`Self::add_embed()`] to add an additional embed.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set multiple embeds for the message.
    ///
    /// **Note**: This will replace all existing embeds. Use [`Self::add_embeds()`] to keep existing
    /// embeds.
    pub fn set_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Delete all embeds in the message, this includes those generated by Discord themselves
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        if suppress {
            self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(1 << 2)));
        } else {
            self.0.remove("flags");
        }

        self
    }

    /// Sets the components of this message.
    #[cfg(feature = "unstable_discord_api")]
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }
}
<commit_msg>Clear the flag when passing `false` to `EditMessage::suppress_embeds` (#1436)<commit_after>use std::collections::HashMap;

use super::CreateEmbed;
#[cfg(feature = "unstable_discord_api")]
use crate::builder::CreateComponents;
use crate::internal::prelude::*;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| {
///     m.content("hello")
/// })
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    fn _add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(Vec::new()));
        let embeds_array = embeds.as_array_mut().expect("Embeds must be an array");

        embeds_array.push(embed);

        self
    }

    /// Add an embed for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embed()`] to replace existing
    /// embeds.
    pub fn add_embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self._add_embed(embed)
    }

    /// Add multiple embeds for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embeds()`] to replace existing
    /// embeds.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::set_embed()`].
    ///
    /// **Note**: This will replace all existing embeds. Use
    /// [`Self::add_embed()`] to add an additional embed.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::embed()`].
    ///
    /// **Note**: This will replace all existing embeds.
    /// Use [`Self::add_embed()`] to add an additional embed.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set multiple embeds for the message.
    ///
    /// **Note**: This will replace all existing embeds. Use [`Self::add_embeds()`] to keep existing
    /// embeds.
    pub fn set_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Suppress or unsuppress embeds in the message, this includes those generated by Discord
    /// themselves.
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        let flags = if suppress { 1 << 2 } else { 0 };
        self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(flags)));

        self
    }

    /// Sets the components of this message.
    #[cfg(feature = "unstable_discord_api")]
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }
}
<|endoftext|>


<commit_before>use core::mem;
use core::sync::atomic::AtomicBool;

use alloc::sync::Arc;

use crate::gdt::{GDT, GDT_USER_FS, GDT_USER_GS};
use crate::paging::{RmmA, RmmArch, TableKind};
use crate::syscall::FloatRegisters;

use memoffset::offset_of;
use spin::Once;

/// This must be used by the kernel to ensure that context switches are done atomically
/// Compare and exchange this to true when beginning a context switch on any CPU
/// The `Context::switch_to` function will set it back to false, allowing other CPU's to switch
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = AtomicBool::new(false);

const ST_RESERVED: u128 = 0xFFFF_FFFF_FFFF_0000_0000_0000_0000_0000;

pub const KFX_SIZE: usize = 512;
pub const KFX_ALIGN: usize = 16;

#[derive(Clone, Debug)]
#[repr(C)]
pub struct Context {
    /// EFLAGS register
    eflags: usize,
    /// EBX register
    ebx: usize,
    /// EDI register
    edi: usize,
    /// ESI register
    esi: usize,
    /// Base pointer
    ebp: usize,
    /// Stack pointer
    pub(crate) esp: usize,
    /// FSBASE.
    ///
    /// NOTE: Same fsgsbase behavior as with gsbase.
    pub(crate) fsbase: usize,
    /// GSBASE.
    ///
    /// NOTE: Without fsgsbase, this register will strictly be equal to the register value when
    /// running. With fsgsbase, this is neither saved nor restored upon every syscall (there is no
    /// need to!), and thus it must be re-read from the register before copying this struct.
    pub(crate) gsbase: usize,
}

impl Context {
    pub fn new() -> Context {
        Context {
            eflags: 0,
            ebx: 0,
            edi: 0,
            esi: 0,
            ebp: 0,
            esp: 0,
            fsbase: 0,
            gsbase: 0,
        }
    }

    pub fn set_stack(&mut self, address: usize) {
        self.esp = address;
    }

    pub unsafe fn signal_stack(&mut self, handler: extern fn(usize), sig: u8) {
        self.push_stack(sig as usize);
        self.push_stack(handler as usize);
        self.push_stack(signal_handler_wrapper as usize);
    }

    pub unsafe fn push_stack(&mut self, value: usize) {
        self.esp -= mem::size_of::<usize>();
        *(self.esp as *mut usize) = value;
    }

    pub unsafe fn pop_stack(&mut self) -> usize {
        let value = *(self.esp as *const usize);
        self.esp += mem::size_of::<usize>();
        value
    }
}
impl super::Context {
    pub fn get_fx_regs(&self) -> FloatRegisters {
        let mut regs = unsafe { self.kfx.as_ptr().cast::<FloatRegisters>().read() };
        regs._reserved = 0;
        let mut new_st = regs.st_space;
        for st in &mut new_st {
            // Only allow access to the 80 lowest bits
            *st &= !ST_RESERVED;
        }
        regs.st_space = new_st;
        regs
    }

    pub fn set_fx_regs(&mut self, mut new: FloatRegisters) {
        {
            let old = unsafe { &*(self.kfx.as_ptr().cast::<FloatRegisters>()) };
            new._reserved = old._reserved;
            let old_st = new.st_space;
            let mut new_st = new.st_space;
            for (new_st, old_st) in new_st.iter_mut().zip(&old_st) {
                *new_st &= !ST_RESERVED;
                *new_st |= old_st & ST_RESERVED;
            }
            new.st_space = new_st;

            // Make sure we don't use `old` from now on
        }

        unsafe {
            self.kfx.as_mut_ptr().cast::<FloatRegisters>().write(new);
        }
    }
}

pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();

// SAFETY: EMPTY_CR3 must be initialized.
pub unsafe fn empty_cr3() -> rmm::PhysicalAddress {
    debug_assert!(EMPTY_CR3.poll().is_some());
    *EMPTY_CR3.get_unchecked()
}

/// Switch to the next context by restoring its stack and registers
pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) {
    core::arch::asm!("
        fxsave [{prev_fx}]
        fxrstor [{next_fx}]
        ", prev_fx = in(reg) prev.kfx.as_mut_ptr(),
        next_fx = in(reg) next.kfx.as_ptr(),
    );

    {
        prev.arch.fsbase = GDT[GDT_USER_FS].offset() as usize;
        GDT[GDT_USER_FS].set_offset(next.arch.fsbase as u32);
        prev.arch.gsbase = GDT[GDT_USER_GS].offset() as usize;
        GDT[GDT_USER_GS].set_offset(next.arch.gsbase as u32);
    }

    match next.addr_space {
        // Since Arc is essentially just wraps a pointer, in this case a regular pointer (as
        // opposed to dyn or slice fat pointers), and NonNull optimization exists, map_or will
        // hopefully be optimized down to checking prev and next pointers, as next cannot be null.
        Some(ref next_space) => if prev.addr_space.as_ref().map_or(true, |prev_space| !Arc::ptr_eq(&prev_space, &next_space)) {
            // Suppose we have two sibling threads A and B. A runs on CPU 0 and B on CPU 1. A
            // recently called yield and is now here about to switch back. Meanwhile, B is
            // currently creating a new mapping in their shared address space, for example a
            // message on a channel.
            //
            // Unless we acquire this lock, it may be possible that the TLB will not contain new
            // entries. While this can be caught and corrected in a page fault handler, this is not
            // true when entries are removed from a page table!
            next_space.read().table.utable.make_current();
        }
        None => {
            RmmA::set_table(TableKind::User, empty_cr3());
        }
    }

    core::arch::asm!(
        "call {inner}",
        inner = sym switch_to_inner,
        in("ecx") &mut prev.arch,
        in("edx") &mut next.arch,
    );
}

// Check disassembly!
#[naked]
unsafe extern "cdecl" fn switch_to_inner() {
    use Context as Cx;

    core::arch::asm!(
        // As a quick reminder for those who are unfamiliar with the System V ABI (extern "C"):
        //
        // - the current parameters are passed in the registers `edi`, `esi`,
        // - we can modify scratch registers, e.g. rax
        // - we cannot change callee-preserved registers arbitrarily, e.g. ebx, which is why we
        //   store them here in the first place.
        concat!("
        // ecx is prev, edx is next

        // Save old registers, and load new ones
        mov [ecx + {off_ebx}], ebx
        mov ebx, [edx + {off_ebx}]

        mov [ecx + {off_edi}], edi
        mov edi, [edx + {off_edi}]

        mov [ecx + {off_esi}], esi
        mov esi, [edx + {off_esi}]

        mov [ecx + {off_ebp}], ebp
        mov ebp, [edx + {off_ebp}]

        mov [ecx + {off_esp}], esp
        mov esp, [edx + {off_esp}]

        // push EFLAGS (can only be modified via stack)
        pushfd
        // pop EFLAGS into `self.eflags`
        pop DWORD PTR [ecx + {off_eflags}]

        // push `next.eflags`
        push DWORD PTR [edx + {off_eflags}]
        // pop into EFLAGS
        popfd

        // When we return, we cannot even guarantee that the return address on the stack, points to
        // the calling function, `context::switch`. Thus, we have to execute this Rust hook by
        // ourselves, which will unlock the contexts before the later switch.

        // Note that switch_finish_hook will be responsible for executing `ret`.
        jmp {switch_hook}

        "),

        off_eflags = const(offset_of!(Cx, eflags)),

        off_ebx = const(offset_of!(Cx, ebx)),
        off_edi = const(offset_of!(Cx, edi)),
        off_esi = const(offset_of!(Cx, esi)),
        off_ebp = const(offset_of!(Cx, ebp)),
        off_esp = const(offset_of!(Cx, esp)),

        switch_hook = sym crate::context::switch_finish_hook,
        options(noreturn),
    );
}
#[allow(dead_code)]
#[repr(packed)]
pub struct SignalHandlerStack {
    edx: usize,
    ecx: usize,
    eax: usize,
    handler: extern fn(usize),
    sig: usize,
    eip: usize,
}

#[naked]
unsafe extern "C" fn signal_handler_wrapper() {
    #[inline(never)]
    unsafe extern "C" fn inner(stack: &SignalHandlerStack) {
        (stack.handler)(stack.sig);
    }

    // Push scratch registers
    core::arch::asm!(
        "
            push eax
            push ecx
            push edx

            push esp
            call {inner}
            pop esp

            pop edx
            pop ecx
            pop eax
            add esp, 8
            ret
        ",

        inner = sym inner,
        options(noreturn),
    );
}
<commit_msg>Use push/pop scratch for x86 signal handler<commit_after>use core::mem;
use core::sync::atomic::AtomicBool;

use alloc::sync::Arc;

use crate::{push_scratch, pop_scratch};
use crate::gdt::{GDT, GDT_USER_FS, GDT_USER_GS};
use crate::interrupt::handler::ScratchRegisters;
use crate::paging::{RmmA, RmmArch, TableKind};
use crate::syscall::FloatRegisters;

use memoffset::offset_of;
use spin::Once;

/// This must be used by the kernel to ensure that context switches are done atomically
/// Compare and exchange this to true when beginning a context switch on any CPU
/// The `Context::switch_to` function will set it back to false, allowing other CPU's to switch
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = AtomicBool::new(false);

const ST_RESERVED: u128 = 0xFFFF_FFFF_FFFF_0000_0000_0000_0000_0000;

pub const KFX_SIZE: usize = 512;
pub const KFX_ALIGN: usize = 16;

#[derive(Clone, Debug)]
#[repr(C)]
pub struct Context {
    /// EFLAGS register
    eflags: usize,
    /// EBX register
    ebx: usize,
    /// EDI register
    edi: usize,
    /// ESI register
    esi: usize,
    /// Base pointer
    ebp: usize,
    /// Stack pointer
    pub(crate) esp: usize,
    /// FSBASE.
    ///
    /// NOTE: Same fsgsbase behavior as with gsbase.
    pub(crate) fsbase: usize,
    /// GSBASE.
    ///
    /// NOTE: Without fsgsbase, this register will strictly be equal to the register value when
    /// running. With fsgsbase, this is neither saved nor restored upon every syscall (there is no
    /// need to!), and thus it must be re-read from the register before copying this struct.
    pub(crate) gsbase: usize,
}

impl Context {
    pub fn new() -> Context {
        Context {
            eflags: 0,
            ebx: 0,
            edi: 0,
            esi: 0,
            ebp: 0,
            esp: 0,
            fsbase: 0,
            gsbase: 0,
        }
    }

    pub fn set_stack(&mut self, address: usize) {
        self.esp = address;
    }

    pub unsafe fn signal_stack(&mut self, handler: extern fn(usize), sig: u8) {
        self.push_stack(sig as usize);
        self.push_stack(handler as usize);
        self.push_stack(signal_handler_wrapper as usize);
    }

    pub unsafe fn push_stack(&mut self, value: usize) {
        self.esp -= mem::size_of::<usize>();
        *(self.esp as *mut usize) = value;
    }

    pub unsafe fn pop_stack(&mut self) -> usize {
        let value = *(self.esp as *const usize);
        self.esp += mem::size_of::<usize>();
        value
    }
}
impl super::Context {
    pub fn get_fx_regs(&self) -> FloatRegisters {
        let mut regs = unsafe { self.kfx.as_ptr().cast::<FloatRegisters>().read() };
        regs._reserved = 0;
        let mut new_st = regs.st_space;
        for st in &mut new_st {
            // Only allow access to the 80 lowest bits
            *st &= !ST_RESERVED;
        }
        regs.st_space = new_st;
        regs
    }

    pub fn set_fx_regs(&mut self, mut new: FloatRegisters) {
        {
            let old = unsafe { &*(self.kfx.as_ptr().cast::<FloatRegisters>()) };
            new._reserved = old._reserved;
            let old_st = new.st_space;
            let mut new_st = new.st_space;
            for (new_st, old_st) in new_st.iter_mut().zip(&old_st) {
                *new_st &= !ST_RESERVED;
                *new_st |= old_st & ST_RESERVED;
            }
            new.st_space = new_st;

            // Make sure we don't use `old` from now on
        }

        unsafe {
            self.kfx.as_mut_ptr().cast::<FloatRegisters>().write(new);
        }
    }
}

pub static EMPTY_CR3: Once<rmm::PhysicalAddress> = Once::new();

// SAFETY: EMPTY_CR3 must be initialized.
pub unsafe fn empty_cr3() -> rmm::PhysicalAddress {
    debug_assert!(EMPTY_CR3.poll().is_some());
    *EMPTY_CR3.get_unchecked()
}

/// Switch to the next context by restoring its stack and registers
pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) {
    core::arch::asm!("
        fxsave [{prev_fx}]
        fxrstor [{next_fx}]
        ", prev_fx = in(reg) prev.kfx.as_mut_ptr(),
        next_fx = in(reg) next.kfx.as_ptr(),
    );

    {
        prev.arch.fsbase = GDT[GDT_USER_FS].offset() as usize;
        GDT[GDT_USER_FS].set_offset(next.arch.fsbase as u32);
        prev.arch.gsbase = GDT[GDT_USER_GS].offset() as usize;
        GDT[GDT_USER_GS].set_offset(next.arch.gsbase as u32);
    }

    match next.addr_space {
        // Since Arc is essentially just wraps a pointer, in this case a regular pointer (as
        // opposed to dyn or slice fat pointers), and NonNull optimization exists, map_or will
        // hopefully be optimized down to checking prev and next pointers, as next cannot be null.
        Some(ref next_space) => if prev.addr_space.as_ref().map_or(true, |prev_space| !Arc::ptr_eq(&prev_space, &next_space)) {
            // Suppose we have two sibling threads A and B. A runs on CPU 0 and B on CPU 1. A
            // recently called yield and is now here about to switch back. Meanwhile, B is
            // currently creating a new mapping in their shared address space, for example a
            // message on a channel.
            //
            // Unless we acquire this lock, it may be possible that the TLB will not contain new
            // entries. While this can be caught and corrected in a page fault handler, this is not
            // true when entries are removed from a page table!
            next_space.read().table.utable.make_current();
        }
        None => {
            RmmA::set_table(TableKind::User, empty_cr3());
        }
    }

    core::arch::asm!(
        "call {inner}",
        inner = sym switch_to_inner,
        in("ecx") &mut prev.arch,
        in("edx") &mut next.arch,
    );
}

// Check disassembly!
#[naked]
unsafe extern "cdecl" fn switch_to_inner() {
    use Context as Cx;

    core::arch::asm!(
        // As a quick reminder for those who are unfamiliar with the System V ABI (extern "C"):
        //
        // - the current parameters are passed in the registers `edi`, `esi`,
        // - we can modify scratch registers, e.g. rax
        // - we cannot change callee-preserved registers arbitrarily, e.g. ebx, which is why we
        //   store them here in the first place.
        concat!("
        // ecx is prev, edx is next

        // Save old registers, and load new ones
        mov [ecx + {off_ebx}], ebx
        mov ebx, [edx + {off_ebx}]

        mov [ecx + {off_edi}], edi
        mov edi, [edx + {off_edi}]

        mov [ecx + {off_esi}], esi
        mov esi, [edx + {off_esi}]

        mov [ecx + {off_ebp}], ebp
        mov ebp, [edx + {off_ebp}]

        mov [ecx + {off_esp}], esp
        mov esp, [edx + {off_esp}]

        // push EFLAGS (can only be modified via stack)
        pushfd
        // pop EFLAGS into `self.eflags`
        pop DWORD PTR [ecx + {off_eflags}]

        // push `next.eflags`
        push DWORD PTR [edx + {off_eflags}]
        // pop into EFLAGS
        popfd

        // When we return, we cannot even guarantee that the return address on the stack, points to
        // the calling function, `context::switch`. Thus, we have to execute this Rust hook by
        // ourselves, which will unlock the contexts before the later switch.

        // Note that switch_finish_hook will be responsible for executing `ret`.
        jmp {switch_hook}

        "),

        off_eflags = const(offset_of!(Cx, eflags)),

        off_ebx = const(offset_of!(Cx, ebx)),
        off_edi = const(offset_of!(Cx, edi)),
        off_esi = const(offset_of!(Cx, esi)),
        off_ebp = const(offset_of!(Cx, ebp)),
        off_esp = const(offset_of!(Cx, esp)),

        switch_hook = sym crate::context::switch_finish_hook,
        options(noreturn),
    );
}
#[allow(dead_code)]
#[repr(packed)]
pub struct SignalHandlerStack {
    scratch: ScratchRegisters,
    handler: extern fn(usize),
    sig: usize,
    eip: usize,
}

#[naked]
unsafe extern "C" fn signal_handler_wrapper() {
    #[inline(never)]
    unsafe extern "C" fn inner(stack: &SignalHandlerStack) {
        (stack.handler)(stack.sig);
    }

    // Push scratch registers
    core::arch::asm!(
        concat!(
            "push eax",
            push_scratch!(),
            "
            push esp
            call {inner}
            pop esp
            ",
            pop_scratch!(),
            "
            add esp, 8
            ret
            ",
        ),
        inner = sym inner,
        options(noreturn),
    );
}
<|endoftext|>


<commit_before><commit_msg>Add missing test cfg<commit_after><|endoftext|>


<commit_before>//! Functions relating to network operations.
//!
//! This will eventually be moved

use std::net::{TcpListener, TcpStream};
use std::thread;

fn start_listening(port: u16) -> Result<TcpListener, &'static str> {

    let listener = TcpListener::bind(("127.0.0.1", port));

    if listener.is_ok() {
        return Ok(listener.unwrap());
    } else {
        return Err("Could not listen on requested port");
    }

}

pub fn start_network() {

    let listener = start_listening(25565);

    if listener.is_err() {
        error!("Could not start listening on port {}", 25565);
    }

    let mut listener = listener.unwrap();

    for stream in listener.incoming() {

        match stream {
            Ok(stream) => {
                thread::spawn(move || {
                    // New connection succeeded
                    handle_new_client(stream)
                });
            }
            Err(e) => {
                error!("Could not accept a new stream");
            }
        }

    }

    drop(listener);

}

pub fn handle_new_client(stream: TcpStream) {
    info!("Got a new client! Oh my!");
}<commit_msg>Debug incoming connections. About to work on NetherrackBuffer<commit_after>//! Functions relating to network operations.
//!
//! This will eventually be moved

use std::net::{Shutdown, TcpListener, TcpStream};
use std::thread;

use std::io::Read;

fn start_listening(port: u16) -> Result<TcpListener, &'static str> {

    let listener = TcpListener::bind(("127.0.0.1", port));

    if listener.is_ok() {
        return Ok(listener.unwrap());
    } else {
        return Err("Could not listen on requested port");
    }

}

pub fn start_network() {

    let listener = start_listening(25565);

    if listener.is_err() {
        error!("Could not start listening on port {}", 25565);
    }

    let listener = listener.unwrap();

    for stream in listener.incoming() {

        match stream {
            Ok(stream) => {
                thread::spawn(move || {
                    // New connection succeeded
                    handle_new_client(stream)
                });
            }
            Err(e) => {
                error!("Could not accept a new stream: {}", e);
            }
        }

    }

    drop(listener);

}

pub fn handle_new_client(mut stream: TcpStream) {
    info!("Got a new client from {}! Oh my!", stream.peer_addr().unwrap());

    loop {

        let mut buffer = [0u8; 512];

        match stream.read(&mut buffer) {

            Err(error) => {
                // Connection dropped out or something broke
                // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them
                // For now, we just exit the loop
                error!("Got an error! {}",  error);

                stream.shutdown(Shutdown::Both);
                break; //Close the connection
            }
            Ok(count) => {
                if (count == 0) {
                    ::std::thread::sleep_ms(2);
                } else {
                    info!("Read {} bytes, information is {}: {}: {}: {}", count, buffer[0], buffer[1], buffer[2], buffer[3]);
                }
            }

        }

    }

    info!("Connection closed");

}<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus::tree::{Factory, MTFn, Tree};

use crate::dbus_api::{
    consts,
    types::{DbusContext, TData},
};

mod fetch_properties_2_1;
mod fetch_properties_2_2;
mod manager_2_0;
mod manager_2_1;
mod manager_2_2;
mod manager_2_3;
mod manager_2_4;
mod report_2_1;
mod shared;

pub fn get_base_tree<'a>(dbus_context: DbusContext) -> (Tree<MTFn<TData>, TData>, dbus::Path<'a>) {
    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let obj_path = f
        .object_path(consts::STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME, ())
                .add_m(manager_2_0::create_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_1, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_1::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_1::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_2, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_1::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_3, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_3::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_4, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_3::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_m(manager_2_4::engine_state_report_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_1, ())
                .add_m(fetch_properties_2_1::get_all_properties_method(&f))
                .add_m(fetch_properties_2_1::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_2, ())
                .add_m(fetch_properties_2_2::get_all_properties_method(&f))
                .add_m(fetch_properties_2_2::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_3, ())
                .add_m(fetch_properties_2_2::get_all_properties_method(&f))
                .add_m(fetch_properties_2_2::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::REPORT_INTERFACE_NAME_2_1, ())
                .add_m(report_2_1::get_report_method(&f)),
        );

    let path = obj_path.get_name().to_owned();
    (base_tree.add(obj_path), path)
}
<commit_msg>Introspect on prefixes of D-Bus path /org/storage/stratis2<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus::tree::{Factory, MTFn, Tree};

use crate::dbus_api::{
    consts,
    types::{DbusContext, TData},
};

mod fetch_properties_2_1;
mod fetch_properties_2_2;
mod manager_2_0;
mod manager_2_1;
mod manager_2_2;
mod manager_2_3;
mod manager_2_4;
mod report_2_1;
mod shared;

pub fn get_base_tree<'a>(dbus_context: DbusContext) -> (Tree<MTFn<TData>, TData>, dbus::Path<'a>) {
    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let obj_path = f.object_path("/", None).introspectable();
    let base_tree = base_tree.add(obj_path);

    let obj_path = f.object_path("/org", None).introspectable();
    let base_tree = base_tree.add(obj_path);

    let obj_path = f.object_path("/org/storage", None).introspectable();
    let base_tree = base_tree.add(obj_path);

    let obj_path = f
        .object_path(consts::STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME, ())
                .add_m(manager_2_0::create_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_1, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_1::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_1::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_2, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_1::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_3, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_3::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::MANAGER_INTERFACE_NAME_2_4, ())
                .add_m(manager_2_1::create_pool_method(&f))
                .add_m(manager_2_2::set_key_method(&f))
                .add_m(manager_2_1::unset_key_method(&f))
                .add_m(manager_2_3::unlock_pool_method(&f))
                .add_m(manager_2_0::destroy_pool_method(&f))
                .add_m(manager_2_0::configure_simulator_method(&f))
                .add_m(manager_2_4::engine_state_report_method(&f))
                .add_p(manager_2_0::version_property(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_1, ())
                .add_m(fetch_properties_2_1::get_all_properties_method(&f))
                .add_m(fetch_properties_2_1::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_2, ())
                .add_m(fetch_properties_2_2::get_all_properties_method(&f))
                .add_m(fetch_properties_2_2::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::PROPERTY_FETCH_INTERFACE_NAME_2_3, ())
                .add_m(fetch_properties_2_2::get_all_properties_method(&f))
                .add_m(fetch_properties_2_2::get_properties_method(&f)),
        )
        .add(
            f.interface(consts::REPORT_INTERFACE_NAME_2_1, ())
                .add_m(report_2_1::get_report_method(&f)),
        );

    let path = obj_path.get_name().to_owned();
    (base_tree.add(obj_path), path)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use char::Char;
use clone::Clone;
use container::Container;
use default::Default;
use finally::try_finally;
use intrinsics;
use iter::{range, Iterator, FromIterator};
use mem;
use num::{CheckedMul, CheckedAdd};
use option::{Some, None};
use ptr::RawPtr;
use ptr;
use raw::Vec;
use slice::ImmutableVector;
use str::StrSlice;

#[cfg(not(test))] use ops::Add;

#[allow(ctypes)]
extern {
    fn rust_malloc(size: uint, align: uint) -> *u8;
    fn rust_free(ptr: *u8, size: uint, align: uint);
}

unsafe fn alloc(cap: uint) -> *mut Vec<()> {
    let cap = cap.checked_add(&mem::size_of::<Vec<()>>()).unwrap();
    // this should use the real alignment, but the new representation will take care of that
    let ret = rust_malloc(cap, 8) as *mut Vec<()>;
    if ret.is_null() {
        intrinsics::abort();
    }
    (*ret).fill = 0;
    (*ret).alloc = cap;
    ret
}

// Strings

impl Default for ~str {
    fn default() -> ~str {
        unsafe {
            // Get some memory
            let ptr = alloc(0);

            // Initialize the memory
            (*ptr).fill = 0;
            (*ptr).alloc = 0;

            mem::transmute(ptr)
        }
    }
}

impl Clone for ~str {
    fn clone(&self) -> ~str {
        // Don't use the clone() implementation above because it'll start
        // requiring the eh_personality lang item (no fun)
        unsafe {
            let bytes = self.as_bytes().as_ptr();
            let len = self.len();

            let ptr = alloc(len) as *mut Vec<u8>;
            ptr::copy_nonoverlapping_memory(&mut (*ptr).data, bytes, len);
            (*ptr).fill = len;
            (*ptr).alloc = len;

            mem::transmute(ptr)
        }
    }
}

impl FromIterator<char> for ~str {
    #[inline]
    fn from_iter<T: Iterator<char>>(mut iterator: T) -> ~str {
        let (lower, _) = iterator.size_hint();
        let mut cap = if lower == 0 {16} else {lower};
        let mut len = 0;
        let mut tmp = [0u8, ..4];

        unsafe {
            let mut ptr = alloc(cap) as *mut Vec<u8>;
            let mut ret = mem::transmute(ptr);
            for ch in iterator {
                let amt = ch.encode_utf8(tmp);

                if len + amt > cap {
                    cap = cap.checked_mul(&2).unwrap();
                    if cap < len + amt {
                        cap = len + amt;
                    }
                    let ptr2 = alloc(cap) as *mut Vec<u8>;
                    ptr::copy_nonoverlapping_memory(&mut (*ptr2).data,
                                                    &(*ptr).data,
                                                    len);
                    // FIXME: #13994: port to the sized deallocation API when available
                    rust_free(ptr as *u8, 0, 8);
                    mem::forget(ret);
                    ret = mem::transmute(ptr2);
                    ptr = ptr2;
                }

                let base = &mut (*ptr).data as *mut u8;
                for byte in tmp.slice_to(amt).iter() {
                    *base.offset(len as int) = *byte;
                    len += 1;
                }
                (*ptr).fill = len;
            }
            ret
        }
    }
}

#[cfg(not(test))]
impl<'a> Add<&'a str,~str> for &'a str {
    #[inline]
    fn add(&self, rhs: & &'a str) -> ~str {
        let amt = self.len().checked_add(&rhs.len()).unwrap();
        unsafe {
            let ptr = alloc(amt) as *mut Vec<u8>;
            let base = &mut (*ptr).data as *mut _;
            ptr::copy_nonoverlapping_memory(base,
                                            self.as_bytes().as_ptr(),
                                            self.len());
            let base = base.offset(self.len() as int);
            ptr::copy_nonoverlapping_memory(base,
                                            rhs.as_bytes().as_ptr(),
                                            rhs.len());
            (*ptr).fill = amt;
            (*ptr).alloc = amt;
            mem::transmute(ptr)
        }
    }
}

// Arrays

impl<A: Clone> Clone for ~[A] {
    #[inline]
    fn clone(&self) -> ~[A] {
        let len = self.len();
        let data_size = len.checked_mul(&mem::size_of::<A>()).unwrap();
        let size = mem::size_of::<Vec<()>>().checked_add(&data_size).unwrap();

        unsafe {
            let ret = alloc(size) as *mut Vec<A>;

            (*ret).fill = len * mem::nonzero_size_of::<A>();
            (*ret).alloc = len * mem::nonzero_size_of::<A>();

            let mut i = 0;
            let p = &mut (*ret).data as *mut _ as *mut A;
            try_finally(
                &mut i, (),
                |i, ()| while *i < len {
                    mem::move_val_init(
                        &mut(*p.offset(*i as int)),
                        self.unsafe_ref(*i).clone());
                    *i += 1;
                },
                |i| if *i < len {
                    // we must be failing, clean up after ourselves
                    for j in range(0, *i as int) {
                        ptr::read(&*p.offset(j));
                    }
                    rust_free(ret as *u8, 0, 8);
                });
            mem::transmute(ret)
        }
    }
}
<commit_msg>core: Document should_not_exist's existence<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// As noted by this file name, this file should not exist. This file should not
// exist because it performs allocations which libcore is not allowed to do. The
// reason for this file's existence is that the `~[T]` and `~str` types are
// language-defined types. Traits are defined in libcore, such as `Clone`, which
// these types need to implement, but the implementation can only be found in
// libcore.
//
// Plan of attack for solving this problem:
//
//      1. Implement DST
//      2. Make `Box<T>` not a language feature
//      3. Move `Box<T>` to a separate crate, liballoc.
//      4. Implement relevant trais in liballoc, not libcore
//
// Currently, no progress has been made on this list.

use char::Char;
use clone::Clone;
use container::Container;
use default::Default;
use finally::try_finally;
use intrinsics;
use iter::{range, Iterator, FromIterator};
use mem;
use num::{CheckedMul, CheckedAdd};
use option::{Some, None};
use ptr::RawPtr;
use ptr;
use raw::Vec;
use slice::ImmutableVector;
use str::StrSlice;

#[cfg(not(test))] use ops::Add;

#[allow(ctypes)]
extern {
    fn rust_malloc(size: uint, align: uint) -> *u8;
    fn rust_free(ptr: *u8, size: uint, align: uint);
}

unsafe fn alloc(cap: uint) -> *mut Vec<()> {
    let cap = cap.checked_add(&mem::size_of::<Vec<()>>()).unwrap();
    // this should use the real alignment, but the new representation will take care of that
    let ret = rust_malloc(cap, 8) as *mut Vec<()>;
    if ret.is_null() {
        intrinsics::abort();
    }
    (*ret).fill = 0;
    (*ret).alloc = cap;
    ret
}

// Strings

impl Default for ~str {
    fn default() -> ~str {
        unsafe {
            // Get some memory
            let ptr = alloc(0);

            // Initialize the memory
            (*ptr).fill = 0;
            (*ptr).alloc = 0;

            mem::transmute(ptr)
        }
    }
}

impl Clone for ~str {
    fn clone(&self) -> ~str {
        // Don't use the clone() implementation above because it'll start
        // requiring the eh_personality lang item (no fun)
        unsafe {
            let bytes = self.as_bytes().as_ptr();
            let len = self.len();

            let ptr = alloc(len) as *mut Vec<u8>;
            ptr::copy_nonoverlapping_memory(&mut (*ptr).data, bytes, len);
            (*ptr).fill = len;
            (*ptr).alloc = len;

            mem::transmute(ptr)
        }
    }
}

impl FromIterator<char> for ~str {
    #[inline]
    fn from_iter<T: Iterator<char>>(mut iterator: T) -> ~str {
        let (lower, _) = iterator.size_hint();
        let mut cap = if lower == 0 {16} else {lower};
        let mut len = 0;
        let mut tmp = [0u8, ..4];

        unsafe {
            let mut ptr = alloc(cap) as *mut Vec<u8>;
            let mut ret = mem::transmute(ptr);
            for ch in iterator {
                let amt = ch.encode_utf8(tmp);

                if len + amt > cap {
                    cap = cap.checked_mul(&2).unwrap();
                    if cap < len + amt {
                        cap = len + amt;
                    }
                    let ptr2 = alloc(cap) as *mut Vec<u8>;
                    ptr::copy_nonoverlapping_memory(&mut (*ptr2).data,
                                                    &(*ptr).data,
                                                    len);
                    // FIXME: #13994: port to the sized deallocation API when available
                    rust_free(ptr as *u8, 0, 8);
                    mem::forget(ret);
                    ret = mem::transmute(ptr2);
                    ptr = ptr2;
                }

                let base = &mut (*ptr).data as *mut u8;
                for byte in tmp.slice_to(amt).iter() {
                    *base.offset(len as int) = *byte;
                    len += 1;
                }
                (*ptr).fill = len;
            }
            ret
        }
    }
}

#[cfg(not(test))]
impl<'a> Add<&'a str,~str> for &'a str {
    #[inline]
    fn add(&self, rhs: & &'a str) -> ~str {
        let amt = self.len().checked_add(&rhs.len()).unwrap();
        unsafe {
            let ptr = alloc(amt) as *mut Vec<u8>;
            let base = &mut (*ptr).data as *mut _;
            ptr::copy_nonoverlapping_memory(base,
                                            self.as_bytes().as_ptr(),
                                            self.len());
            let base = base.offset(self.len() as int);
            ptr::copy_nonoverlapping_memory(base,
                                            rhs.as_bytes().as_ptr(),
                                            rhs.len());
            (*ptr).fill = amt;
            (*ptr).alloc = amt;
            mem::transmute(ptr)
        }
    }
}

// Arrays

impl<A: Clone> Clone for ~[A] {
    #[inline]
    fn clone(&self) -> ~[A] {
        let len = self.len();
        let data_size = len.checked_mul(&mem::size_of::<A>()).unwrap();
        let size = mem::size_of::<Vec<()>>().checked_add(&data_size).unwrap();

        unsafe {
            let ret = alloc(size) as *mut Vec<A>;

            (*ret).fill = len * mem::nonzero_size_of::<A>();
            (*ret).alloc = len * mem::nonzero_size_of::<A>();

            let mut i = 0;
            let p = &mut (*ret).data as *mut _ as *mut A;
            try_finally(
                &mut i, (),
                |i, ()| while *i < len {
                    mem::move_val_init(
                        &mut(*p.offset(*i as int)),
                        self.unsafe_ref(*i).clone());
                    *i += 1;
                },
                |i| if *i < len {
                    // we must be failing, clean up after ourselves
                    for j in range(0, *i as int) {
                        ptr::read(&*p.offset(j));
                    }
                    rust_free(ret as *u8, 0, 8);
                });
            mem::transmute(ret)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Markdown formatting for rustdoc
//!
//! This module implements markdown formatting through the sundown C-library
//! (bundled into the rust runtime). This module self-contains the C bindings
//! and necessary legwork to render markdown, and exposes all of the
//! functionality through a unit-struct, `Markdown`, which has an implementation
//! of `fmt::Default`. Example usage:
//!
//! ```rust
//! let s = "My *markdown* _text_";
//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```

use std::cast;
use std::fmt;
use std::io;
use std::libc;
use std::str;
use std::unstable::intrinsics;
use std::vec;

/// A unit struct which has the `fmt::Default` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
pub struct Markdown<'a>(&'a str);

static OUTPUT_UNIT: libc::size_t = 64;
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
static MKDEXT_TABLES: libc::c_uint = 1 << 1;
static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;

type sd_markdown = libc::c_void;  // this is opaque to us

struct sd_callbacks {
    blockcode: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
    other: [libc::size_t, ..25],
}

struct html_toc_data {
    header_count: libc::c_int,
    current_level: libc::c_int,
    level_offset: libc::c_int,
}

struct html_renderopt {
    toc_data: html_toc_data,
    flags: libc::c_uint,
    link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
}

struct my_opaque {
    opt: html_renderopt,
    dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
}

struct buf {
    data: *u8,
    size: libc::size_t,
    asize: libc::size_t,
    unit: libc::size_t,
}

// sundown FFI
#[link(name = "sundown", kind = "static")]
extern {
    fn sdhtml_renderer(callbacks: *sd_callbacks,
                       options_ptr: *html_renderopt,
                       render_flags: libc::c_uint);
    fn sd_markdown_new(extensions: libc::c_uint,
                       max_nesting: libc::size_t,
                       callbacks: *sd_callbacks,
                       opaque: *libc::c_void) -> *sd_markdown;
    fn sd_markdown_render(ob: *buf,
                          document: *u8,
                          doc_size: libc::size_t,
                          md: *sd_markdown);
    fn sd_markdown_free(md: *sd_markdown);

    fn bufnew(unit: libc::size_t) -> *buf;
    fn bufrelease(b: *buf);

}

pub fn render(w: &mut io::Writer, s: &str) {
    extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            let my_opaque: &my_opaque = cast::transmute(opaque);
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let text = str::from_utf8(text);
                let mut lines = text.lines().filter(|l| {
                    !l.trim().starts_with("# ")
                });
                let text = lines.to_owned_vec().connect("\n");

                let buf = buf {
                    data: text.as_bytes().as_ptr(),
                    size: text.len() as libc::size_t,
                    asize: text.len() as libc::size_t,
                    unit: 0,
                };
                (my_opaque.dfltblk)(ob, &buf, lang, opaque);
            })
        }
    }

    // This code is all lifted from examples/sundown.c in the sundown repo
    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let options = html_renderopt {
            toc_data: html_toc_data {
                header_count: 0,
                current_level: 0,
                level_offset: 0,
            },
            flags: 0,
            link_attributes: None,
        };
        let mut callbacks: sd_callbacks = intrinsics::init();

        sdhtml_renderer(&callbacks, &options, 0);
        let opaque = my_opaque {
            opt: options,
            dfltblk: callbacks.blockcode,
        };
        callbacks.blockcode = block;
        let markdown = sd_markdown_new(extensions, 16, &callbacks,
                                       &opaque as *my_opaque as *libc::c_void);

        sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
        sd_markdown_free(markdown);

        vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
            w.write(buf);
        });

        bufrelease(ob);
    }
}

pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
    extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            if text.is_null() || lang.is_null() { return }
            let (test, shouldfail, ignore) =
                vec::raw::buf_as_slice((*lang).data,
                                       (*lang).size as uint, |lang| {
                    let s = str::from_utf8(lang);
                    (s.contains("rust"), s.contains("should_fail"),
                     s.contains("ignore"))
                });
            if !test { return }
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let tests: &mut ::test::Collector = intrinsics::transmute(opaque);
                let text = str::from_utf8(text);
                let mut lines = text.lines().map(|l| {
                            if l.starts_with("# ") {l.slice_from(2)} else {l}
                        });
                let text = lines.to_owned_vec().connect("\n");
                tests.add_test(text, ignore, shouldfail);
            })
        }
    }

    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let callbacks = sd_callbacks {
            blockcode: block,
            other: intrinsics::init()
        };

        let tests = tests as *mut ::test::Collector as *libc::c_void;
        let markdown = sd_markdown_new(extensions, 16, &callbacks, tests);

        sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t,
                           markdown);
        sd_markdown_free(markdown);
        bufrelease(ob);
    }
}

impl<'a> fmt::Default for Markdown<'a> {
    fn fmt(md: &Markdown<'a>, fmt: &mut fmt::Formatter) {
        // This is actually common enough to special-case
        if md.len() == 0 { return; }
        render(fmt.buf, md.as_slice());
    }
}
<commit_msg>rustdoc: Unify the handling of the hidden example lines.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Markdown formatting for rustdoc
//!
//! This module implements markdown formatting through the sundown C-library
//! (bundled into the rust runtime). This module self-contains the C bindings
//! and necessary legwork to render markdown, and exposes all of the
//! functionality through a unit-struct, `Markdown`, which has an implementation
//! of `fmt::Default`. Example usage:
//!
//! ```rust
//! let s = "My *markdown* _text_";
//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```

use std::cast;
use std::fmt;
use std::io;
use std::libc;
use std::str;
use std::unstable::intrinsics;
use std::vec;

/// A unit struct which has the `fmt::Default` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
pub struct Markdown<'a>(&'a str);

static OUTPUT_UNIT: libc::size_t = 64;
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
static MKDEXT_TABLES: libc::c_uint = 1 << 1;
static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;

type sd_markdown = libc::c_void;  // this is opaque to us

struct sd_callbacks {
    blockcode: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
    other: [libc::size_t, ..25],
}

struct html_toc_data {
    header_count: libc::c_int,
    current_level: libc::c_int,
    level_offset: libc::c_int,
}

struct html_renderopt {
    toc_data: html_toc_data,
    flags: libc::c_uint,
    link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
}

struct my_opaque {
    opt: html_renderopt,
    dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
}

struct buf {
    data: *u8,
    size: libc::size_t,
    asize: libc::size_t,
    unit: libc::size_t,
}

// sundown FFI
#[link(name = "sundown", kind = "static")]
extern {
    fn sdhtml_renderer(callbacks: *sd_callbacks,
                       options_ptr: *html_renderopt,
                       render_flags: libc::c_uint);
    fn sd_markdown_new(extensions: libc::c_uint,
                       max_nesting: libc::size_t,
                       callbacks: *sd_callbacks,
                       opaque: *libc::c_void) -> *sd_markdown;
    fn sd_markdown_render(ob: *buf,
                          document: *u8,
                          doc_size: libc::size_t,
                          md: *sd_markdown);
    fn sd_markdown_free(md: *sd_markdown);

    fn bufnew(unit: libc::size_t) -> *buf;
    fn bufrelease(b: *buf);

}

/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
/// `s` that should be used in tests. (None for lines that should be
/// left as-is.)
fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
    let trimmed = s.trim();
    if trimmed.starts_with("# ") {
        Some(trimmed.slice_from(2))
    } else {
        None
    }
}

pub fn render(w: &mut io::Writer, s: &str) {
    extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            let my_opaque: &my_opaque = cast::transmute(opaque);
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let text = str::from_utf8(text);
                let mut lines = text.lines().filter(|l| stripped_filtered_line(*l).is_none());
                let text = lines.to_owned_vec().connect("\n");

                let buf = buf {
                    data: text.as_bytes().as_ptr(),
                    size: text.len() as libc::size_t,
                    asize: text.len() as libc::size_t,
                    unit: 0,
                };
                (my_opaque.dfltblk)(ob, &buf, lang, opaque);
            })
        }
    }

    // This code is all lifted from examples/sundown.c in the sundown repo
    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let options = html_renderopt {
            toc_data: html_toc_data {
                header_count: 0,
                current_level: 0,
                level_offset: 0,
            },
            flags: 0,
            link_attributes: None,
        };
        let mut callbacks: sd_callbacks = intrinsics::init();

        sdhtml_renderer(&callbacks, &options, 0);
        let opaque = my_opaque {
            opt: options,
            dfltblk: callbacks.blockcode,
        };
        callbacks.blockcode = block;
        let markdown = sd_markdown_new(extensions, 16, &callbacks,
                                       &opaque as *my_opaque as *libc::c_void);

        sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
        sd_markdown_free(markdown);

        vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
            w.write(buf);
        });

        bufrelease(ob);
    }
}

pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
    extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            if text.is_null() || lang.is_null() { return }
            let (test, shouldfail, ignore) =
                vec::raw::buf_as_slice((*lang).data,
                                       (*lang).size as uint, |lang| {
                    let s = str::from_utf8(lang);
                    (s.contains("rust"), s.contains("should_fail"),
                     s.contains("ignore"))
                });
            if !test { return }
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let tests: &mut ::test::Collector = intrinsics::transmute(opaque);
                let text = str::from_utf8(text);
                let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l));
                let text = lines.to_owned_vec().connect("\n");
                tests.add_test(text, ignore, shouldfail);
            })
        }
    }

    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let callbacks = sd_callbacks {
            blockcode: block,
            other: intrinsics::init()
        };

        let tests = tests as *mut ::test::Collector as *libc::c_void;
        let markdown = sd_markdown_new(extensions, 16, &callbacks, tests);

        sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t,
                           markdown);
        sd_markdown_free(markdown);
        bufrelease(ob);
    }
}

impl<'a> fmt::Default for Markdown<'a> {
    fn fmt(md: &Markdown<'a>, fmt: &mut fmt::Formatter) {
        // This is actually common enough to special-case
        if md.len() == 0 { return; }
        render(fmt.buf, md.as_slice());
    }
}
<|endoftext|>


<commit_before>#![unstable(issue = "0", feature = "windows_stdio")]

use cell::Cell;
use cmp;
use io;
use ptr;
use str;
use sys::c;
use sys::cvt;
use sys::handle::Handle;

// Don't cache handles but get them fresh for every read/write. This allows us to track changes to
// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
pub struct Stdin {
    high_surrogate: Cell<u16>,
}
pub struct Stdout;
pub struct Stderr;

// Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
// #13304 for details).
//
// From MSDN (2011): "The storage for this buffer is allocated from a shared heap for the
// process that is 64 KB in size. The maximum size of the buffer will depend on heap usage."
//
// We choose the cap at 8 KiB because libuv does the same, and it seems to be acceptable so far.
const MAX_BUFFER_SIZE: usize = 8192;

// The standard buffer size of BufReader for Stdin should be able to hold 3x more bytes than there
// are `u16`'s in MAX_BUFFER_SIZE. This ensures the read data can always be completely decoded from
// UTF-16 to UTF-8.
pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;

pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
    let handle = unsafe { c::GetStdHandle(handle_id) };
    if handle == c::INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else if handle.is_null() {
        Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
    } else {
        Ok(handle)
    }
}

fn is_console(handle: c::HANDLE) -> bool {
    // `GetConsoleMode` will return false (0) if this is a pipe (we don't care about the reported
    // mode). This will only detect Windows Console, not other terminals connected to a pipe like
    // MSYS. Which is exactly what we need, as only Windows Console needs a conversion to UTF-16.
    let mut mode = 0;
    unsafe { c::GetConsoleMode(handle, &mut mode) != 0 }
}

fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
    let handle = get_handle(handle_id)?;
    if !is_console(handle) {
        let handle = Handle::new(handle);
        let ret = handle.write(data);
        handle.into_raw(); // Don't close the handle
        return ret;
    }

    // As the console is meant for presenting text, we assume bytes of `data` come from a string
    // and are encoded as UTF-8, which needs to be encoded as UTF-16.
    //
    // If the data is not valid UTF-8 we write out as many bytes as are valid.
    // Only when there are no valid bytes (which will happen on the next call), return an error.
    let len = cmp::min(data.len(), MAX_BUFFER_SIZE);
    let utf8 = match str::from_utf8(&data[..len]) {
        Ok(s) => s,
        Err(ref e) if e.valid_up_to() == 0 => {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                "Windows stdio in console mode does not support non-UTF-8 byte sequences; \
                see https://github.com/rust-lang/rust/issues/23344"))
        },
        Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(),
    };
    let utf16 = utf8.encode_utf16().collect::<Vec<u16>>();

    let mut written = write_u16s(handle, &utf16)?;

    // Figure out how many bytes of as UTF-8 were written away as UTF-16.
    if written >= utf16.len() {
        Ok(utf8.len())
    } else {
        // Make sure we didn't end up writing only half of a surrogate pair (even though the chance
        // is tiny). Because it is not possible for user code to re-slice `data` in such a way that
        // a missing surrogate can be produced (and also because of the UTF-8 validation above),
        // write the missing surrogate out now.
        // Buffering it would mean we have to lie about the number of bytes written.
        let first_char_remaining = utf16[written];
        if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF { // low surrogate
            // We just hope this works, and give up otherwise
            let _ = write_u16s(handle, &utf16[written..written]);
            written += 1;
        }
        // Calculate the number of bytes of `utf8` that were actually written.
        let mut count = 0;
        for ch in utf16[..written].iter() {
            count += match ch {
                0x0000 ..= 0x007F => 1,
                0x0080 ..= 0x07FF => 2,
                0xDCEE ..= 0xDFFF => 1, // Low surrogate. We already counted 3 bytes for the other.
                _ => 3,
            };
        }
        Ok(count)
    }
}

fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
    let mut written = 0;
    cvt(unsafe {
        c::WriteConsoleW(handle,
                         data.as_ptr() as c::LPCVOID,
                         data.len() as u32,
                         &mut written,
                         ptr::null_mut())
    })?;
    Ok(written as usize)
}

impl Stdin {
    pub fn new() -> io::Result<Stdin> {
        Ok(Stdin { high_surrogate: Cell::new(0) })
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let handle = get_handle(c::STD_INPUT_HANDLE)?;
        if !is_console(handle) {
            let handle = Handle::new(handle);
            let ret = handle.read(buf);
            handle.into_raw(); // Don't close the handle
            return ret;
        }

        if buf.len() == 0 {
            return Ok(0);
        } else if buf.len() < 4 {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                        "Windows stdin in console mode does not support a buffer too small to; \
                        guarantee holding one arbitrary UTF-8 character (4 bytes)"))
        }

        let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
        // In the worst case, an UTF-8 string can take 3 bytes for every `u16` of an UTF-16. So
        // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
        // lost.
        let amount = cmp::min(buf.len() / 3, utf16_buf.len());
        let read = self.read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount)?;
        let utf16 = &utf16_buf[..read];

        // FIXME: it would be nice if we could directly decode into the buffer instead of doing an
        //        allocation.
        let data = match String::from_utf16(&utf16) {
            Ok(utf8) => utf8.into_bytes(),
            Err(..) => {
                // We can't really do any better than forget all data and return an error.
                return Err(io::Error::new(io::ErrorKind::InvalidData,
                    "Windows stdin in console mode does not support non-UTF-16 input; \
                    encountered unpaired surrogate"))
            },
        };
        buf.copy_from_slice(&data);
        Ok(data.len())
    }

    // We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our
    // buffer size, and keep it around for the next read hoping to put them together.
    // This is a best effort, and may not work if we are not the only reader on Stdin.
    pub fn read_u16s_fixup_surrogates(&self, handle: c::HANDLE, buf: &mut [u16], mut amount: usize)
        -> io::Result<usize>
    {
        // Insert possibly remaining unpaired surrogate from last read.
        let mut start = 0;
        if self.high_surrogate.get() != 0 {
            buf[0] = self.high_surrogate.replace(0);
            start = 1;
            if amount == 1 {
                // Special case: `Stdin::read` guarantees we can always read at least one new `u16`
                // and combine it with an unpaired surrogate, because the UTF-8 buffer is at least
                // 4 bytes.
                amount = 2;
            }
        }
        let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;

        if amount > 0 {
            let last_char = buf[amount - 1];
            if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate
                self.high_surrogate.set(last_char);
                amount -= 1;
            }
        }
        Ok(amount)
    }
}

fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
    // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the
    // traditional DOS method to indicate end of character stream / user input (SUB).
    // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
    const CTRL_Z: u16 = 0x1A;
    const CTRL_Z_MASK: c::ULONG = 1 << CTRL_Z;
    let mut input_control = c::CONSOLE_READCONSOLE_CONTROL {
        nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
        nInitialChars: 0,
        dwCtrlWakeupMask: CTRL_Z_MASK,
        dwControlKeyState: 0,
    };

    let mut amount = 0;
    cvt(unsafe {
        c::ReadConsoleW(handle,
                        buf.as_mut_ptr() as c::LPVOID,
                        buf.len() as u32,
                        &mut amount,
                        &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
    })?;

    if amount > 0 && buf[amount as usize - 1] == CTRL_Z {
        amount -= 1;
    }
    Ok(amount as usize)
}

impl Stdout {
    pub fn new() -> io::Result<Stdout> {
        Ok(Stdout)
    }

    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
        write(c::STD_OUTPUT_HANDLE, data)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }
}

impl Stderr {
    pub fn new() -> io::Result<Stderr> {
        Ok(Stderr)
    }

    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
        write(c::STD_ERROR_HANDLE, data)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }
}

pub fn is_ebadf(err: &io::Error) -> bool {
    err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
}

pub fn panic_output() -> Option<impl io::Write> {
    io::stderr_raw().ok()
}
<commit_msg>Address review comments<commit_after>#![unstable(issue = "0", feature = "windows_stdio")]

use cell::Cell;
use char::decode_utf16;
use cmp;
use io;
use ptr;
use str;
use sys::c;
use sys::cvt;
use sys::handle::Handle;

// Don't cache handles but get them fresh for every read/write. This allows us to track changes to
// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
pub struct Stdin {
    high_surrogate: Cell<u16>,
}
pub struct Stdout;
pub struct Stderr;

// Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
// #13304 for details).
//
// From MSDN (2011): "The storage for this buffer is allocated from a shared heap for the
// process that is 64 KB in size. The maximum size of the buffer will depend on heap usage."
//
// We choose the cap at 8 KiB because libuv does the same, and it seems to be acceptable so far.
const MAX_BUFFER_SIZE: usize = 8192;

// The standard buffer size of BufReader for Stdin should be able to hold 3x more bytes than there
// are `u16`'s in MAX_BUFFER_SIZE. This ensures the read data can always be completely decoded from
// UTF-16 to UTF-8.
pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;

pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
    let handle = unsafe { c::GetStdHandle(handle_id) };
    if handle == c::INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else if handle.is_null() {
        Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
    } else {
        Ok(handle)
    }
}

fn is_console(handle: c::HANDLE) -> bool {
    // `GetConsoleMode` will return false (0) if this is a pipe (we don't care about the reported
    // mode). This will only detect Windows Console, not other terminals connected to a pipe like
    // MSYS. Which is exactly what we need, as only Windows Console needs a conversion to UTF-16.
    let mut mode = 0;
    unsafe { c::GetConsoleMode(handle, &mut mode) != 0 }
}

fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
    let handle = get_handle(handle_id)?;
    if !is_console(handle) {
        let handle = Handle::new(handle);
        let ret = handle.write(data);
        handle.into_raw(); // Don't close the handle
        return ret;
    }

    // As the console is meant for presenting text, we assume bytes of `data` come from a string
    // and are encoded as UTF-8, which needs to be encoded as UTF-16.
    //
    // If the data is not valid UTF-8 we write out as many bytes as are valid.
    // Only when there are no valid bytes (which will happen on the next call), return an error.
    let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2);
    let utf8 = match str::from_utf8(&data[..len]) {
        Ok(s) => s,
        Err(ref e) if e.valid_up_to() == 0 => {
            return Err(io::Error::new(io::ErrorKind::InvalidData,
                "Windows stdio in console mode does not support writing non-UTF-8 byte sequences"))
        },
        Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(),
    };
    let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2];
    let mut len_utf16 = 0;
    for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
        *dest = chr;
        len_utf16 += 1;
    }
    let utf16 = &utf16[..len_utf16];

    let mut written = write_u16s(handle, &utf16)?;

    // Figure out how many bytes of as UTF-8 were written away as UTF-16.
    if written == utf16.len() {
        Ok(utf8.len())
    } else {
        // Make sure we didn't end up writing only half of a surrogate pair (even though the chance
        // is tiny). Because it is not possible for user code to re-slice `data` in such a way that
        // a missing surrogate can be produced (and also because of the UTF-8 validation above),
        // write the missing surrogate out now.
        // Buffering it would mean we have to lie about the number of bytes written.
        let first_char_remaining = utf16[written];
        if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF { // low surrogate
            // We just hope this works, and give up otherwise
            let _ = write_u16s(handle, &utf16[written..written+1]);
            written += 1;
        }
        // Calculate the number of bytes of `utf8` that were actually written.
        let mut count = 0;
        for ch in utf16[..written].iter() {
            count += match ch {
                0x0000 ..= 0x007F => 1,
                0x0080 ..= 0x07FF => 2,
                0xDCEE ..= 0xDFFF => 1, // Low surrogate. We already counted 3 bytes for the other.
                _ => 3,
            };
        }
        debug_assert!(String::from_utf16(&utf16[..written]).unwrap() == utf8[..count]);
        Ok(count)
    }
}

fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
    let mut written = 0;
    cvt(unsafe {
        c::WriteConsoleW(handle,
                         data.as_ptr() as c::LPCVOID,
                         data.len() as u32,
                         &mut written,
                         ptr::null_mut())
    })?;
    Ok(written as usize)
}

impl Stdin {
    pub fn new() -> io::Result<Stdin> {
        Ok(Stdin { high_surrogate: Cell::new(0) })
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let handle = get_handle(c::STD_INPUT_HANDLE)?;
        if !is_console(handle) {
            let handle = Handle::new(handle);
            let ret = handle.read(buf);
            handle.into_raw(); // Don't close the handle
            return ret;
        }

        if buf.len() == 0 {
            return Ok(0);
        } else if buf.len() < 4 {
            return Err(io::Error::new(io::ErrorKind::InvalidInput,
                        "Windows stdin in console mode does not support a buffer too small to \
                        guarantee holding one arbitrary UTF-8 character (4 bytes)"))
        }

        let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
        // In the worst case, an UTF-8 string can take 3 bytes for every `u16` of an UTF-16. So
        // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
        // lost.
        let amount = cmp::min(buf.len() / 3, utf16_buf.len());
        let read = self.read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount)?;

        utf16_to_utf8(&utf16_buf[..read], buf)
    }

    // We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our
    // buffer size, and keep it around for the next read hoping to put them together.
    // This is a best effort, and may not work if we are not the only reader on Stdin.
    fn read_u16s_fixup_surrogates(&self, handle: c::HANDLE, buf: &mut [u16], mut amount: usize)
        -> io::Result<usize>
    {
        // Insert possibly remaining unpaired surrogate from last read.
        let mut start = 0;
        if self.high_surrogate.get() != 0 {
            buf[0] = self.high_surrogate.replace(0);
            start = 1;
            if amount == 1 {
                // Special case: `Stdin::read` guarantees we can always read at least one new `u16`
                // and combine it with an unpaired surrogate, because the UTF-8 buffer is at least
                // 4 bytes.
                amount = 2;
            }
        }
        let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;

        if amount > 0 {
            let last_char = buf[amount - 1];
            if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate
                self.high_surrogate.set(last_char);
                amount -= 1;
            }
        }
        Ok(amount)
    }
}

fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
    // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the
    // traditional DOS method to indicate end of character stream / user input (SUB).
    // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
    const CTRL_Z: u16 = 0x1A;
    const CTRL_Z_MASK: c::ULONG = 1 << CTRL_Z;
    let mut input_control = c::CONSOLE_READCONSOLE_CONTROL {
        nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
        nInitialChars: 0,
        dwCtrlWakeupMask: CTRL_Z_MASK,
        dwControlKeyState: 0,
    };

    let mut amount = 0;
    cvt(unsafe {
        c::ReadConsoleW(handle,
                        buf.as_mut_ptr() as c::LPVOID,
                        buf.len() as u32,
                        &mut amount,
                        &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
    })?;

    if amount > 0 && buf[amount as usize - 1] == CTRL_Z {
        amount -= 1;
    }
    Ok(amount as usize)
}

#[allow(unused)]
fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
    let mut written = 0;
    for chr in decode_utf16(utf16.iter().cloned()) {
        match chr {
            Ok(chr) => {
                chr.encode_utf8(&mut utf8[written..]);
                written += chr.len_utf8();
            }
            Err(_) => {
                // We can't really do any better than forget all data and return an error.
                return Err(io::Error::new(io::ErrorKind::InvalidData,
                    "Windows stdin in console mode does not support non-UTF-16 input; \
                    encountered unpaired surrogate"))
            }
        }
    }
    Ok(written)
}

impl Stdout {
    pub fn new() -> io::Result<Stdout> {
        Ok(Stdout)
    }

    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
        write(c::STD_OUTPUT_HANDLE, data)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }
}

impl Stderr {
    pub fn new() -> io::Result<Stderr> {
        Ok(Stderr)
    }

    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
        write(c::STD_ERROR_HANDLE, data)
    }

    pub fn flush(&self) -> io::Result<()> {
        Ok(())
    }
}

pub fn is_ebadf(err: &io::Error) -> bool {
    err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
}

pub fn panic_output() -> Option<impl io::Write> {
    io::stderr_raw().ok()
}
<|endoftext|>


<commit_before>use std::ffi::CStr;
use std::fmt;
use ffi::cs_strerror;

#[repr(C)]
/// Architectures for the disassembler
pub enum CsArch {
    ARCH_ARM = 0, // ARM architecture (including Thumb, Thumb-2)
    ARCH_ARM64, // ARM-64, also called AArch64
    ARCH_MIPS, // Mips architecture
    ARCH_X86, // X86 architecture (including x86 & x86-64)
    ARCH_PPC, // PowerPC architecture
    ARCH_SPARC, // Sparc architecture
    ARCH_SYSZ, // SystemZ architecture
    ARCH_XCORE, // XCore architecture
    ARCH_MAX,
    ARCH_ALL = 0xFFFF, // All architectures - for cs_support()
}

#[repr(C)]
/// Disassembler modes
pub enum CsMode {
    MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
    // MODE_ARM = 0,    // 32-bit ARM
    MODE_16 = 1 << 1, // 16-bit mode (X86)
    MODE_32 = 1 << 2, // 32-bit mode (X86)
    MODE_64 = 1 << 3, // 64-bit mode (X86, PPC)
    MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
    MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
    MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
    // MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
    // MODE_MIPS3 = 1 << 5, // Mips III ISA
    // MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
    // MODE_MIPSGP64 = 1 << 7, // General Purpose Registers are 64-bit wide (MIPS)
    // MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
    MODE_BIG_ENDIAN = 1 << 31, /* big-endian mode
                                * MODE_MIPS32 = CsMode::MODE_32,    // Mips32 ISA (Mips)
                                * MODE_MIPS64 = CsMode::MODE_64,    // Mips64 ISA (Mips) */
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Eq)]
/// Error states returned by various disassembler features
pub enum CsErr {
    CS_ERR_OK = 0, // No error: everything was fine
    CS_ERR_MEM, // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    CS_ERR_ARCH, // Unsupported architecture: cs_open()
    CS_ERR_HANDLE, // Invalid handle: cs_op_count(), cs_op_index()
    CS_ERR_CSH, // Invalid csh argument: cs_close(), cs_errno(), cs_option()
    CS_ERR_MODE, // Invalid/unsupported mode: cs_open()
    CS_ERR_OPTION, // Invalid/unsupported option: cs_option()
    CS_ERR_DETAIL, // Information is unavailable because detail option is OFF
    CS_ERR_MEMSETUP, // Dynamic memory management uninitialized (see CS_OPT_MEM)
    CS_ERR_VERSION, // Unsupported version (bindings)
    CS_ERR_DIET, // Access irrelevant data in "diet" engine
    CS_ERR_SKIPDATA, // Access irrelevant data for "data" instruction in SKIPDATA mode
    CS_ERR_X86_ATT, // X86 AT&T syntax is unsupported (opt-out at compile time)
    CS_ERR_X86_INTEL, // X86 Intel syntax is unsupported (opt-out at compile time)
}

impl fmt::Display for CsErr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let s = unsafe {
            let err = cs_strerror(*self);
            CStr::from_ptr(err).to_string_lossy().into_owned()
        };
        write!(fmt, "{}", s)
    }
}
<commit_msg>Make CsErr Debug<commit_after>use std::ffi::CStr;
use std::fmt;
use ffi::cs_strerror;

#[repr(C)]
/// Architectures for the disassembler
pub enum CsArch {
    ARCH_ARM = 0, // ARM architecture (including Thumb, Thumb-2)
    ARCH_ARM64, // ARM-64, also called AArch64
    ARCH_MIPS, // Mips architecture
    ARCH_X86, // X86 architecture (including x86 & x86-64)
    ARCH_PPC, // PowerPC architecture
    ARCH_SPARC, // Sparc architecture
    ARCH_SYSZ, // SystemZ architecture
    ARCH_XCORE, // XCore architecture
    ARCH_MAX,
    ARCH_ALL = 0xFFFF, // All architectures - for cs_support()
}

#[repr(C)]
/// Disassembler modes
pub enum CsMode {
    MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
    // MODE_ARM = 0,    // 32-bit ARM
    MODE_16 = 1 << 1, // 16-bit mode (X86)
    MODE_32 = 1 << 2, // 32-bit mode (X86)
    MODE_64 = 1 << 3, // 64-bit mode (X86, PPC)
    MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
    MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
    MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
    // MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
    // MODE_MIPS3 = 1 << 5, // Mips III ISA
    // MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
    // MODE_MIPSGP64 = 1 << 7, // General Purpose Registers are 64-bit wide (MIPS)
    // MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
    MODE_BIG_ENDIAN = 1 << 31, /* big-endian mode
                                * MODE_MIPS32 = CsMode::MODE_32,    // Mips32 ISA (Mips)
                                * MODE_MIPS64 = CsMode::MODE_64,    // Mips64 ISA (Mips) */
}

#[repr(C)]
#[derive(Clone,Copy,PartialEq,Eq,Debug)]
/// Error states returned by various disassembler features
pub enum CsErr {
    CS_ERR_OK = 0, // No error: everything was fine
    CS_ERR_MEM, // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    CS_ERR_ARCH, // Unsupported architecture: cs_open()
    CS_ERR_HANDLE, // Invalid handle: cs_op_count(), cs_op_index()
    CS_ERR_CSH, // Invalid csh argument: cs_close(), cs_errno(), cs_option()
    CS_ERR_MODE, // Invalid/unsupported mode: cs_open()
    CS_ERR_OPTION, // Invalid/unsupported option: cs_option()
    CS_ERR_DETAIL, // Information is unavailable because detail option is OFF
    CS_ERR_MEMSETUP, // Dynamic memory management uninitialized (see CS_OPT_MEM)
    CS_ERR_VERSION, // Unsupported version (bindings)
    CS_ERR_DIET, // Access irrelevant data in "diet" engine
    CS_ERR_SKIPDATA, // Access irrelevant data for "data" instruction in SKIPDATA mode
    CS_ERR_X86_ATT, // X86 AT&T syntax is unsupported (opt-out at compile time)
    CS_ERR_X86_INTEL, // X86 Intel syntax is unsupported (opt-out at compile time)
}

impl fmt::Display for CsErr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let s = unsafe {
            let err = cs_strerror(*self);
            CStr::from_ptr(err).to_string_lossy().into_owned()
        };
        write!(fmt, "{}", s)
    }
}
<|endoftext|>