<commit_before>// Copyright 2021 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.

use std::collections::VecDeque;
use std::io::{self, stdin};
use std::ops::DerefMut;
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use base::{error, warn, Event, FileSync, RawDescriptor, Terminal};
use cros_async::{EventAsync, Executor};
use data_model::DataInit;

use argh::FromArgs;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::serial_device::{
    SerialDevice, SerialHardware, SerialInput, SerialParameters, SerialType,
};
use crate::virtio::console::{
    handle_input, process_transmit_queue, spawn_input_thread, virtio_console_config, ConsoleError,
};
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::vhost::user::device::vvu::pci::VvuPciDevice;
use crate::virtio::{self, copy_config, SignalableInterrupt};

async fn run_tx_queue<I: SignalableInterrupt>(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    doorbell: I,
    kick_evt: EventAsync,
    mut output: Box<dyn io::Write>,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for tx queue: {}", e);
            break;
        }
        process_transmit_queue(&mem, &doorbell, &mut queue, &mut output);
    }
}

async fn run_rx_queue<I: SignalableInterrupt>(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    doorbell: I,
    kick_evt: EventAsync,
    in_buffer: Arc<Mutex<VecDeque<u8>>>,
    in_avail_evt: EventAsync,
) {
    loop {
        if let Err(e) = in_avail_evt.next_val().await {
            error!("Failed reading in_avail_evt: {}", e);
            break;
        }
        match handle_input(&mem, &doorbell, in_buffer.lock().deref_mut(), &mut queue) {
            Ok(()) => {}
            Err(ConsoleError::RxDescriptorsExhausted) => {
                if let Err(e) = kick_evt.next_val().await {
                    error!("Failed to read kick event for rx queue: {}", e);
                    break;
                }
            }
        }
    }
}

struct ConsoleDevice {
    input: Option<Box<dyn SerialInput>>,
    output: Option<Box<dyn io::Write + Send>>,
    avail_features: u64,
}

impl SerialDevice for ConsoleDevice {
    fn new(
        protected_vm: ProtectionType,
        _evt: Event,
        input: Option<Box<dyn SerialInput>>,
        output: Option<Box<dyn io::Write + Send>>,
        _sync: Option<Box<dyn FileSync + Send>>,
        _out_timestamp: bool,
        _keep_rds: Vec<RawDescriptor>,
    ) -> ConsoleDevice {
        let avail_features =
            virtio::base_features(protected_vm) | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
        ConsoleDevice {
            input,
            output,
            avail_features,
        }
    }
}

struct ConsoleBackend {
    ex: Executor,
    device: ConsoleDevice,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; Self::MAX_QUEUE_NUM],
}

impl ConsoleBackend {
    fn new(ex: &Executor, device: ConsoleDevice) -> Self {
        Self {
            ex: ex.clone(),
            device,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
        }
    }
}

impl VhostUserBackend for ConsoleBackend {
    const MAX_QUEUE_NUM: usize = 2; /* transmit and receive queues */
    const MAX_VRING_LEN: u16 = 256;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.device.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.device.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let config = virtio_console_config {
            max_nr_ports: 1.into(),
            ..Default::default()
        };
        copy_config(data, 0, config.as_slice(), offset);
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt = EventAsync::new(kick_evt, &self.ex)
            .context("Failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            // ReceiveQueue
            0 => {
                // See explanation in devices/src/virtio/console.rs
                // We need a multithreaded input polling because io::Read only provides
                // a blocking interface which we cannot use in an async function.
                let in_avail_evt = match Event::new() {
                    Ok(evt) => evt,
                    Err(e) => {
                        bail!("Failed creating Event: {}", e);
                    }
                };

                let input_unpacked = self
                    .device
                    .input
                    .take()
                    .ok_or_else(|| anyhow!("input source unavailable"))?;
                let in_buffer = spawn_input_thread(input_unpacked, &in_avail_evt)
                    .take()
                    .ok_or_else(|| anyhow!("input channel unavailable"))?;

                // Create the async 'in' event so we can await on it.
                let in_avail_async_evt = EventAsync::new(in_avail_evt, &self.ex)
                    .context("Failed to create EventAsync for in_avail_evt")?;

                self.ex
                    .spawn_local(Abortable::new(
                        run_rx_queue(
                            queue,
                            mem,
                            doorbell,
                            kick_evt,
                            in_buffer,
                            in_avail_async_evt,
                        ),
                        registration,
                    ))
                    .detach();
            }
            // TransmitQueue
            1 => {
                // Take ownership of output writer.
                // Safe because output should always be initialized to something
                let output_unwrapped: Box<dyn io::Write + Send> = self
                    .device
                    .output
                    .take()
                    .ok_or_else(|| anyhow!("no output available"))?;
                self.ex
                    .spawn_local(Abortable::new(
                        run_tx_queue(queue, mem, doorbell, kick_evt, output_unwrapped),
                        registration,
                    ))
                    .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
}

#[derive(FromArgs)]
#[argh(description = "")]
struct Options {
    #[argh(option, description = "path to a vhost-user socket", arg_name = "PATH")]
    socket: Option<String>,
    #[argh(
        option,
        description = "VFIO-PCI device name (e.g. '0000:00:07.0')",
        arg_name = "STRING"
    )]
    vfio: Option<String>,
    #[argh(option, description = "path to a file", arg_name = "OUTFILE")]
    output_file: Option<PathBuf>,
    #[argh(option, description = "path to a file", arg_name = "INFILE")]
    input_file: Option<PathBuf>,
}

/// Starts a vhost-user console device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_console_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };

    let type_ = match opts.output_file {
        Some(_) => SerialType::File,
        None => SerialType::Stdout,
    };

    let params = SerialParameters {
        type_,
        hardware: SerialHardware::VirtioConsole,
        // Required only if type_ is SerialType::File or SerialType::UnixSocket
        path: opts.output_file,
        input: opts.input_file,
        num: 1,
        console: true,
        earlycon: false,
        // We do not support stdin-less mode
        stdin: true,
        out_timestamp: false,
    };

    let console = match params.create_serial_device::<ConsoleDevice>(
        ProtectionType::Unprotected,
        // We need to pass an event as per Serial Device API but we don't really use it anyway.
        &Event::new()?,
        // Same for keep_rds, we don't really use this.
        &mut Vec::new(),
    ) {
        Ok(c) => c,
        Err(e) => bail!(e),
    };
    let ex = Executor::new().context("Failed to create executor")?;
    let backend = ConsoleBackend::new(&ex, console);
    let handler = DeviceRequestHandler::new(backend);

    // Set stdin() in raw mode so we can send over individual keystrokes unbuffered
    stdin()
        .set_raw_mode()
        .context("Failed to set terminal raw mode")?;

    let res = match (opts.socket, opts.vfio) {
        (Some(socket), None) => {
            // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
            ex.run_until(handler.run(socket, &ex))?
        }
        (None, Some(vfio)) => {
            let device = VvuPciDevice::new(&vfio, ConsoleBackend::MAX_QUEUE_NUM)?;
            ex.run_until(handler.run_vvu(device, &ex))?
        }
        _ => Err(anyhow!("exactly one of `--socket` or `--vfio` is required")),
    };

    // Restore terminal capabilities back to what they were before
    stdin()
        .set_canon_mode()
        .context("Failed to restore canonical mode for terminal")?;

    res
}
<commit_msg>devices: vhost-user: console: poll input asynchronously<commit_after>// Copyright 2021 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.

use std::collections::VecDeque;
use std::io::{self, stdin};
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use base::{error, warn, AsRawDescriptor, Event, FileSync, RawDescriptor, Terminal};
use cros_async::{EventAsync, Executor, IntoAsync, IoSourceExt};
use data_model::DataInit;

use argh::FromArgs;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::serial_device::{
    SerialDevice, SerialHardware, SerialInput, SerialParameters, SerialType,
};
use crate::virtio::console::{
    handle_input, process_transmit_queue, virtio_console_config, ConsoleError,
};
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::vhost::user::device::vvu::pci::VvuPciDevice;
use crate::virtio::{self, copy_config, SignalableInterrupt};

/// Wrapper that makes any `SerialInput` usable as an async source by providing an implementation of
/// `IntoAsync`.
struct AsyncSerialInput(Box<dyn SerialInput>);
impl AsRawDescriptor for AsyncSerialInput {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.0.as_raw_descriptor()
    }
}
impl IntoAsync for AsyncSerialInput {}

async fn run_tx_queue<I: SignalableInterrupt>(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    doorbell: I,
    kick_evt: EventAsync,
    mut output: Box<dyn io::Write>,
) {
    loop {
        if let Err(e) = kick_evt.next_val().await {
            error!("Failed to read kick event for tx queue: {}", e);
            break;
        }
        process_transmit_queue(&mem, &doorbell, &mut queue, &mut output);
    }
}

async fn run_rx_queue<I: SignalableInterrupt>(
    mut queue: virtio::Queue,
    mem: GuestMemory,
    doorbell: I,
    kick_evt: EventAsync,
    input: Box<dyn IoSourceExt<AsyncSerialInput>>,
) {
    // Staging buffer, required because of `handle_input`'s API. We can probably remove this once
    // the regular virtio device is switched to async.
    let mut in_buffer = VecDeque::<u8>::new();
    let mut rx_buf = vec![0u8; 4096];
    let mut input_offset = 0u64;

    loop {
        match input.as_ref().read_to_vec(Some(input_offset), rx_buf).await {
            // Input source has closed.
            Ok((0, _)) => break,
            Ok((size, v)) => {
                in_buffer.extend(&v[0..size]);
                input_offset += size as u64;
                rx_buf = v;
            }
            Err(e) => {
                error!("Failed to read console input: {}", e);
                return;
            }
        }

        // Submit all the data obtained during this read.
        while !in_buffer.is_empty() {
            match handle_input(&mem, &doorbell, &mut in_buffer, &mut queue) {
                Ok(()) => {}
                Err(ConsoleError::RxDescriptorsExhausted) => {
                    // Wait until a descriptor becomes available and try again.
                    if let Err(e) = kick_evt.next_val().await {
                        error!("Failed to read kick event for rx queue: {}", e);
                        return;
                    }
                }
            }
        }
    }
}

struct ConsoleDevice {
    input: Option<Box<dyn SerialInput>>,
    output: Option<Box<dyn io::Write + Send>>,
    avail_features: u64,
}

impl SerialDevice for ConsoleDevice {
    fn new(
        protected_vm: ProtectionType,
        _evt: Event,
        input: Option<Box<dyn SerialInput>>,
        output: Option<Box<dyn io::Write + Send>>,
        _sync: Option<Box<dyn FileSync + Send>>,
        _out_timestamp: bool,
        _keep_rds: Vec<RawDescriptor>,
    ) -> ConsoleDevice {
        let avail_features =
            virtio::base_features(protected_vm) | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
        ConsoleDevice {
            input,
            output,
            avail_features,
        }
    }
}

struct ConsoleBackend {
    ex: Executor,
    device: ConsoleDevice,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; Self::MAX_QUEUE_NUM],
}

impl ConsoleBackend {
    fn new(ex: &Executor, device: ConsoleDevice) -> Self {
        Self {
            ex: ex.clone(),
            device,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
        }
    }
}

impl VhostUserBackend for ConsoleBackend {
    const MAX_QUEUE_NUM: usize = 2; /* transmit and receive queues */
    const MAX_VRING_LEN: u16 = 256;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.device.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.device.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let config = virtio_console_config {
            max_nr_ports: 1.into(),
            ..Default::default()
        };
        copy_config(data, 0, config.as_slice(), offset);
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt = EventAsync::new(kick_evt, &self.ex)
            .context("Failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            // ReceiveQueue
            0 => {
                let input_unpacked = self
                    .device
                    .input
                    .take()
                    .ok_or_else(|| anyhow!("input source unavailable"))?;
                let async_input = self
                    .ex
                    .async_from(AsyncSerialInput(input_unpacked))
                    .context("failed to create async console input")?;

                self.ex
                    .spawn_local(Abortable::new(
                        run_rx_queue(queue, mem, doorbell, kick_evt, async_input),
                        registration,
                    ))
                    .detach();
            }
            // TransmitQueue
            1 => {
                // Take ownership of output writer.
                // Safe because output should always be initialized to something
                let output_unwrapped: Box<dyn io::Write + Send> = self
                    .device
                    .output
                    .take()
                    .ok_or_else(|| anyhow!("no output available"))?;
                self.ex
                    .spawn_local(Abortable::new(
                        run_tx_queue(queue, mem, doorbell, kick_evt, output_unwrapped),
                        registration,
                    ))
                    .detach();
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
    }
}

#[derive(FromArgs)]
#[argh(description = "")]
struct Options {
    #[argh(option, description = "path to a vhost-user socket", arg_name = "PATH")]
    socket: Option<String>,
    #[argh(
        option,
        description = "VFIO-PCI device name (e.g. '0000:00:07.0')",
        arg_name = "STRING"
    )]
    vfio: Option<String>,
    #[argh(option, description = "path to a file", arg_name = "OUTFILE")]
    output_file: Option<PathBuf>,
    #[argh(option, description = "path to a file", arg_name = "INFILE")]
    input_file: Option<PathBuf>,
}

/// Starts a vhost-user console device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_console_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };

    let type_ = match opts.output_file {
        Some(_) => SerialType::File,
        None => SerialType::Stdout,
    };

    let params = SerialParameters {
        type_,
        hardware: SerialHardware::VirtioConsole,
        // Required only if type_ is SerialType::File or SerialType::UnixSocket
        path: opts.output_file,
        input: opts.input_file,
        num: 1,
        console: true,
        earlycon: false,
        // We do not support stdin-less mode
        stdin: true,
        out_timestamp: false,
    };

    let console = match params.create_serial_device::<ConsoleDevice>(
        ProtectionType::Unprotected,
        // We need to pass an event as per Serial Device API but we don't really use it anyway.
        &Event::new()?,
        // Same for keep_rds, we don't really use this.
        &mut Vec::new(),
    ) {
        Ok(c) => c,
        Err(e) => bail!(e),
    };
    let ex = Executor::new().context("Failed to create executor")?;
    let backend = ConsoleBackend::new(&ex, console);
    let handler = DeviceRequestHandler::new(backend);

    // Set stdin() in raw mode so we can send over individual keystrokes unbuffered
    stdin()
        .set_raw_mode()
        .context("Failed to set terminal raw mode")?;

    let res = match (opts.socket, opts.vfio) {
        (Some(socket), None) => {
            // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
            ex.run_until(handler.run(socket, &ex))?
        }
        (None, Some(vfio)) => {
            let device = VvuPciDevice::new(&vfio, ConsoleBackend::MAX_QUEUE_NUM)?;
            ex.run_until(handler.run_vvu(device, &ex))?
        }
        _ => Err(anyhow!("exactly one of `--socket` or `--vfio` is required")),
    };

    // Restore terminal capabilities back to what they were before
    stdin()
        .set_canon_mode()
        .context("Failed to restore canonical mode for terminal")?;

    res
}
<|endoftext|>


<commit_before>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use anyhow::bail;
use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::{cmd, cp, pushd};
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client[=CLIENT] Install only VS Code plugin.
                          CLIENT is one of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'
        --server          Install only the language server
        --mimalloc        Use mimalloc allocator for server
        --jemalloc        Use jemalloc allocator for server
    -h, --help            Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc = if args.contains("--mimalloc") {
                Malloc::Mimalloc
            } else if args.contains("--jemalloc") {
                Malloc::Jemalloc
            } else {
                Malloc::System
            };

            let client_opt = args.opt_value_from_str("--client")?;

            finish_args(args)?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            finish_args(args)?;
            CodegenCmd { features }.run()
        }
        "format" => {
            finish_args(args)?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            finish_args(args)?;
            pre_commit::install_hook()
        }
        "lint" => {
            finish_args(args)?;
            run_clippy()
        }
        "fuzz-tests" => {
            finish_args(args)?;
            run_fuzzer()
        }
        "pre-cache" => {
            finish_args(args)?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            finish_args(args)?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            MetricsCmd { dry_run }.run()
        }
        "bb" => {
            let suffix: String = args.free_from_str()?;
            finish_args(args)?;
            cmd!("cargo build --release").run()?;
            cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?;
            Ok(())
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote
    bb"
            );
            Ok(())
        }
    }
}

fn finish_args(args: Arguments) -> Result<()> {
    if !args.finish().is_empty() {
        bail!("Unused arguments.");
    }
    Ok(())
}
<commit_msg>reliable memory usage during benchmarking<commit_after>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use anyhow::bail;
use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::{cmd, cp, pushd};
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client[=CLIENT] Install only VS Code plugin.
                          CLIENT is one of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'
        --server          Install only the language server
        --mimalloc        Use mimalloc allocator for server
        --jemalloc        Use jemalloc allocator for server
    -h, --help            Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc = if args.contains("--mimalloc") {
                Malloc::Mimalloc
            } else if args.contains("--jemalloc") {
                Malloc::Jemalloc
            } else {
                Malloc::System
            };

            let client_opt = args.opt_value_from_str("--client")?;

            finish_args(args)?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            finish_args(args)?;
            CodegenCmd { features }.run()
        }
        "format" => {
            finish_args(args)?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            finish_args(args)?;
            pre_commit::install_hook()
        }
        "lint" => {
            finish_args(args)?;
            run_clippy()
        }
        "fuzz-tests" => {
            finish_args(args)?;
            run_fuzzer()
        }
        "pre-cache" => {
            finish_args(args)?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            finish_args(args)?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            finish_args(args)?;
            MetricsCmd { dry_run }.run()
        }
        "bb" => {
            let suffix: String = args.free_from_str()?;
            finish_args(args)?;
            {
                let _d = pushd("./crates/rust-analyzer")?;
                cmd!("cargo build --release --features jemalloc").run()?;
            }
            cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", suffix))?;
            Ok(())
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote
    bb"
            );
            Ok(())
        }
    }
}

fn finish_args(args: Arguments) -> Result<()> {
    if !args.finish().is_empty() {
        bail!("Unused arguments.");
    }
    Ok(())
}
<|endoftext|>


<commit_before>use io;
use std::string::String;
use super::{
	Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, Uint8,
	ValueType, TableElementType
};

const FLAG_HAS_MAX: u8 = 0x01;
const FLAG_SHARED: u8 = 0x02;

/// Global definition struct
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct GlobalType {
	content_type: ValueType,
	is_mutable: bool,
}

impl GlobalType {
	/// New global type
	pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
		GlobalType {
			content_type: content_type,
			is_mutable: is_mutable,
		}
	}

	/// Type of the global entry
	pub fn content_type(&self) -> ValueType { self.content_type }

	/// Is global entry is declared as mutable
	pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let content_type = ValueType::deserialize(reader)?;
		let is_mutable = VarUint1::deserialize(reader)?;
		Ok(GlobalType {
			content_type: content_type,
			is_mutable: is_mutable.into(),
		})
	}
}

impl Serialize for GlobalType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.content_type.serialize(writer)?;
		VarUint1::from(self.is_mutable).serialize(writer)?;
		Ok(())
	}
}

/// Table entry
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TableType {
	elem_type: TableElementType,
	limits: ResizableLimits,
}

impl TableType {
	/// New table definition
	pub fn new(min: u32, max: Option<u32>) -> Self {
		TableType {
			elem_type: TableElementType::AnyFunc,
			limits: ResizableLimits::new(min, max),
		}
	}

	/// Table memory specification
	pub fn limits(&self) -> &ResizableLimits { &self.limits }

	/// Table element type
	pub fn elem_type(&self) -> TableElementType { self.elem_type }
}

impl Deserialize for TableType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let elem_type = TableElementType::deserialize(reader)?;
		let limits = ResizableLimits::deserialize(reader)?;
		Ok(TableType {
			elem_type: elem_type,
			limits: limits,
		})
	}
}

impl Serialize for TableType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.elem_type.serialize(writer)?;
		self.limits.serialize(writer)
	}
}

/// Memory and table limits.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ResizableLimits {
	initial: u32,
	maximum: Option<u32>,
	shared: bool,
}

impl ResizableLimits {
	/// New memory limits definition.
	pub fn new(min: u32, max: Option<u32>) -> Self {
		ResizableLimits {
			initial: min,
			maximum: max,
			shared: false,
		}
	}
	/// Initial size.
	pub fn initial(&self) -> u32 { self.initial }
	/// Maximum size.
	pub fn maximum(&self) -> Option<u32> { self.maximum }
	/// Whether or not this is a shared array buffer.
	pub fn shared(&self) -> bool { self.shared }
}

impl Deserialize for ResizableLimits {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let flags: u8 = Uint8::deserialize(reader)?.into();
		match flags {
			0x00 | 0x01 | 0x03 => {},
			_ => return Err(Error::InvalidLimitsFlags(flags)),
		}

		let initial = VarUint32::deserialize(reader)?;
		let maximum = if flags & FLAG_HAS_MAX != 0 {
			Some(VarUint32::deserialize(reader)?.into())
		} else {
			None
		};
		let shared = flags & FLAG_SHARED != 0;

		Ok(ResizableLimits {
			initial: initial.into(),
			maximum: maximum,
			shared,
		})
	}
}

impl Serialize for ResizableLimits {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		let mut flags: u8 = 0;
		if self.maximum.is_some() {
			flags |= FLAG_HAS_MAX;
		}
		if self.shared {
			flags |= FLAG_SHARED;
		}
		Uint8::from(flags).serialize(writer)?;
		VarUint32::from(self.initial).serialize(writer)?;
		if let Some(max) = self.maximum {
			VarUint32::from(max).serialize(writer)?;
		}
		Ok(())
	}
}

/// Memory entry.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct MemoryType(ResizableLimits);

impl MemoryType {
	/// New memory definition
	pub fn new(min: u32, max: Option<u32>, shared: bool) -> Self {
		let mut r = ResizableLimits::new(min, max);
		r.shared = shared;
		MemoryType(r)
	}

	/// Limits of the memory entry.
	pub fn limits(&self) -> &ResizableLimits {
		&self.0
	}
}

impl Deserialize for MemoryType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		Ok(MemoryType(ResizableLimits::deserialize(reader)?))
	}
}

impl Serialize for MemoryType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.0.serialize(writer)
	}
}

/// External to local binding.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum External {
	/// Binds to function with index.
	Function(u32),
	/// Describes local table definition to be imported as.
	Table(TableType),
	/// Describes local memory definition to be imported as.
	Memory(MemoryType),
	/// Describes local global entry to be imported as.
	Global(GlobalType),
}

impl Deserialize for External {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let kind = VarUint7::deserialize(reader)?;
		match kind.into() {
			0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
			0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
			0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
			0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
			_ => Err(Error::UnknownExternalKind(kind.into())),
		}
	}
}

impl Serialize for External {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		use self::External::*;

		match self {
			Function(index) => {
				VarUint7::from(0x00).serialize(writer)?;
				VarUint32::from(index).serialize(writer)?;
			},
			Table(tt) => {
				VarInt7::from(0x01).serialize(writer)?;
				tt.serialize(writer)?;
			},
			Memory(mt) => {
				VarInt7::from(0x02).serialize(writer)?;
				mt.serialize(writer)?;
			},
			Global(gt) => {
				VarInt7::from(0x03).serialize(writer)?;
				gt.serialize(writer)?;
			},
		}

		Ok(())
	}
}

/// Import entry.
#[derive(Debug, Clone, PartialEq)]
pub struct ImportEntry {
	module_str: String,
	field_str: String,
	external: External,
}

impl ImportEntry {
	/// New import entry.
	pub fn new(module_str: String, field_str: String, external: External) -> Self {
		ImportEntry {
			module_str: module_str,
			field_str: field_str,
			external: external,
		}
	}

	/// Module reference of the import entry.
	pub fn module(&self) -> &str { &self.module_str }

	/// Module reference of the import entry (mutable).
	pub fn module_mut(&mut self) -> &mut String {
		&mut self.module_str
	}

	/// Field reference of the import entry.
	pub fn field(&self) -> &str { &self.field_str }

	/// Field reference of the import entry (mutable)
	pub fn field_mut(&mut self) -> &mut String {
		&mut self.field_str
	}

	/// Local binidng of the import entry.
	pub fn external(&self) -> &External { &self.external }

	/// Local binidng of the import entry (mutable)
	pub fn external_mut(&mut self) -> &mut External { &mut self.external }
}

impl Deserialize for ImportEntry {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let module_str = String::deserialize(reader)?;
		let field_str = String::deserialize(reader)?;
		let external = External::deserialize(reader)?;

		Ok(ImportEntry {
			module_str: module_str,
			field_str: field_str,
			external: external,
		})
	}
}

impl Serialize for ImportEntry {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.module_str.serialize(writer)?;
		self.field_str.serialize(writer)?;
		self.external.serialize(writer)
	}
}
<commit_msg>Clarify that `External::Function`'s index is its type, not a local function<commit_after>use io;
use std::string::String;
use super::{
	Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, Uint8,
	ValueType, TableElementType
};

const FLAG_HAS_MAX: u8 = 0x01;
const FLAG_SHARED: u8 = 0x02;

/// Global definition struct
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct GlobalType {
	content_type: ValueType,
	is_mutable: bool,
}

impl GlobalType {
	/// New global type
	pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
		GlobalType {
			content_type: content_type,
			is_mutable: is_mutable,
		}
	}

	/// Type of the global entry
	pub fn content_type(&self) -> ValueType { self.content_type }

	/// Is global entry is declared as mutable
	pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let content_type = ValueType::deserialize(reader)?;
		let is_mutable = VarUint1::deserialize(reader)?;
		Ok(GlobalType {
			content_type: content_type,
			is_mutable: is_mutable.into(),
		})
	}
}

impl Serialize for GlobalType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.content_type.serialize(writer)?;
		VarUint1::from(self.is_mutable).serialize(writer)?;
		Ok(())
	}
}

/// Table entry
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TableType {
	elem_type: TableElementType,
	limits: ResizableLimits,
}

impl TableType {
	/// New table definition
	pub fn new(min: u32, max: Option<u32>) -> Self {
		TableType {
			elem_type: TableElementType::AnyFunc,
			limits: ResizableLimits::new(min, max),
		}
	}

	/// Table memory specification
	pub fn limits(&self) -> &ResizableLimits { &self.limits }

	/// Table element type
	pub fn elem_type(&self) -> TableElementType { self.elem_type }
}

impl Deserialize for TableType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let elem_type = TableElementType::deserialize(reader)?;
		let limits = ResizableLimits::deserialize(reader)?;
		Ok(TableType {
			elem_type: elem_type,
			limits: limits,
		})
	}
}

impl Serialize for TableType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.elem_type.serialize(writer)?;
		self.limits.serialize(writer)
	}
}

/// Memory and table limits.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ResizableLimits {
	initial: u32,
	maximum: Option<u32>,
	shared: bool,
}

impl ResizableLimits {
	/// New memory limits definition.
	pub fn new(min: u32, max: Option<u32>) -> Self {
		ResizableLimits {
			initial: min,
			maximum: max,
			shared: false,
		}
	}
	/// Initial size.
	pub fn initial(&self) -> u32 { self.initial }
	/// Maximum size.
	pub fn maximum(&self) -> Option<u32> { self.maximum }
	/// Whether or not this is a shared array buffer.
	pub fn shared(&self) -> bool { self.shared }
}

impl Deserialize for ResizableLimits {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let flags: u8 = Uint8::deserialize(reader)?.into();
		match flags {
			0x00 | 0x01 | 0x03 => {},
			_ => return Err(Error::InvalidLimitsFlags(flags)),
		}

		let initial = VarUint32::deserialize(reader)?;
		let maximum = if flags & FLAG_HAS_MAX != 0 {
			Some(VarUint32::deserialize(reader)?.into())
		} else {
			None
		};
		let shared = flags & FLAG_SHARED != 0;

		Ok(ResizableLimits {
			initial: initial.into(),
			maximum: maximum,
			shared,
		})
	}
}

impl Serialize for ResizableLimits {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		let mut flags: u8 = 0;
		if self.maximum.is_some() {
			flags |= FLAG_HAS_MAX;
		}
		if self.shared {
			flags |= FLAG_SHARED;
		}
		Uint8::from(flags).serialize(writer)?;
		VarUint32::from(self.initial).serialize(writer)?;
		if let Some(max) = self.maximum {
			VarUint32::from(max).serialize(writer)?;
		}
		Ok(())
	}
}

/// Memory entry.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct MemoryType(ResizableLimits);

impl MemoryType {
	/// New memory definition
	pub fn new(min: u32, max: Option<u32>, shared: bool) -> Self {
		let mut r = ResizableLimits::new(min, max);
		r.shared = shared;
		MemoryType(r)
	}

	/// Limits of the memory entry.
	pub fn limits(&self) -> &ResizableLimits {
		&self.0
	}
}

impl Deserialize for MemoryType {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		Ok(MemoryType(ResizableLimits::deserialize(reader)?))
	}
}

impl Serialize for MemoryType {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.0.serialize(writer)
	}
}

/// External to local binding.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum External {
	/// Binds to a function whose type is associated with the given index in the
	/// type section.
	Function(u32),
	/// Describes local table definition to be imported as.
	Table(TableType),
	/// Describes local memory definition to be imported as.
	Memory(MemoryType),
	/// Describes local global entry to be imported as.
	Global(GlobalType),
}

impl Deserialize for External {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let kind = VarUint7::deserialize(reader)?;
		match kind.into() {
			0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
			0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
			0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
			0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
			_ => Err(Error::UnknownExternalKind(kind.into())),
		}
	}
}

impl Serialize for External {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		use self::External::*;

		match self {
			Function(index) => {
				VarUint7::from(0x00).serialize(writer)?;
				VarUint32::from(index).serialize(writer)?;
			},
			Table(tt) => {
				VarInt7::from(0x01).serialize(writer)?;
				tt.serialize(writer)?;
			},
			Memory(mt) => {
				VarInt7::from(0x02).serialize(writer)?;
				mt.serialize(writer)?;
			},
			Global(gt) => {
				VarInt7::from(0x03).serialize(writer)?;
				gt.serialize(writer)?;
			},
		}

		Ok(())
	}
}

/// Import entry.
#[derive(Debug, Clone, PartialEq)]
pub struct ImportEntry {
	module_str: String,
	field_str: String,
	external: External,
}

impl ImportEntry {
	/// New import entry.
	pub fn new(module_str: String, field_str: String, external: External) -> Self {
		ImportEntry {
			module_str: module_str,
			field_str: field_str,
			external: external,
		}
	}

	/// Module reference of the import entry.
	pub fn module(&self) -> &str { &self.module_str }

	/// Module reference of the import entry (mutable).
	pub fn module_mut(&mut self) -> &mut String {
		&mut self.module_str
	}

	/// Field reference of the import entry.
	pub fn field(&self) -> &str { &self.field_str }

	/// Field reference of the import entry (mutable)
	pub fn field_mut(&mut self) -> &mut String {
		&mut self.field_str
	}

	/// Local binidng of the import entry.
	pub fn external(&self) -> &External { &self.external }

	/// Local binidng of the import entry (mutable)
	pub fn external_mut(&mut self) -> &mut External { &mut self.external }
}

impl Deserialize for ImportEntry {
	type Error = Error;

	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let module_str = String::deserialize(reader)?;
		let field_str = String::deserialize(reader)?;
		let external = External::deserialize(reader)?;

		Ok(ImportEntry {
			module_str: module_str,
			field_str: field_str,
			external: external,
		})
	}
}

impl Serialize for ImportEntry {
	type Error = Error;

	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
		self.module_str.serialize(writer)?;
		self.field_str.serialize(writer)?;
		self.external.serialize(writer)
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 * - main kernel entry point and top level management
 *
 * vim:ts=4:sw=4:et:tw=80:ft=rust
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

#![crate_type="lib"]
#![feature(core)]
#![feature(asm)]
#![feature(no_std)]
#![feature(lang_items)]
#![no_std]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

use terminal::color;
use terminal::Terminal;

mod terminal;

#[no_mangle]
pub extern fn kernel_main() -> ! {

    terminal::initialize();
    terminal::set_color(color::RED, color::WHITE);

    terminal::write("+ Hello, I'm Kit.\n");

    let result: Result<(), &str> = Err("foo");

    result.unwrap();

    unreachable!();
}

#[lang = "stack_exhausted"]
extern fn stack_exhausted() {
}

#[lang = "eh_personality"]
extern fn eh_personality() {
}

#[lang = "panic_fmt"]
#[allow(unused_must_use)]
extern fn panic_fmt(fmt: core::fmt::Arguments,
                    file: &'static str,
                    line: usize) -> ! {

    terminal::set_color(color::WHITE, color::RED);

    write!(&mut Terminal, "\nKernel panic in {}:{}:\n  {}\n\n", file, line, fmt);

    unsafe {
        asm!("cli");

        loop {
            asm!("hlt");
        }
    }
}
<commit_msg>[kernel] make mod(s) public<commit_after>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 * - main kernel entry point and top level management
 *
 * vim:ts=4:sw=4:et:tw=80:ft=rust
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

#![crate_type="lib"]
#![feature(core)]
#![feature(asm)]
#![feature(no_std)]
#![feature(lang_items)]
#![no_std]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

use terminal::color;
use terminal::Terminal;

pub mod terminal;

#[no_mangle]
pub extern fn kernel_main() -> ! {

    terminal::initialize();
    terminal::set_color(color::RED, color::WHITE);

    terminal::write("+ Hello, I'm Kit.\n");

    let result: Result<(), &str> = Err("foo");

    result.unwrap();

    unreachable!();
}

#[lang = "stack_exhausted"]
extern fn stack_exhausted() {
}

#[lang = "eh_personality"]
extern fn eh_personality() {
}

#[lang = "panic_fmt"]
#[allow(unused_must_use)]
extern fn panic_fmt(fmt: core::fmt::Arguments,
                    file: &'static str,
                    line: usize) -> ! {

    terminal::set_color(color::WHITE, color::RED);

    write!(&mut Terminal, "\nKernel panic in {}:{}:\n  {}\n\n", file, line, fmt);

    unsafe {
        asm!("cli");

        loop {
            asm!("hlt");
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{
        space::{Space, SpaceElement},
        window::{draw_window, Window},
    },
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::TypeId,
    cell::{RefCell, RefMut},
    collections::HashMap,
};

use super::RenderZindex;

#[derive(Default)]
pub struct WindowState {
    pub location: Point<i32, Logical>,
    pub drawn: bool,
}

pub type WindowUserdata = RefCell<HashMap<usize, WindowState>>;
pub fn window_state(space: usize, w: &Window) -> RefMut<'_, WindowState> {
    let userdata = w.user_data();
    userdata.insert_if_missing(WindowUserdata::default);
    RefMut::map(userdata.get::<WindowUserdata>().unwrap().borrow_mut(), |m| {
        m.entry(space).or_default()
    })
}

pub fn window_geo(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.geometry();
    wgeo.loc = loc;
    wgeo
}

pub fn window_rect(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.bbox();
    wgeo.loc += loc;
    wgeo
}

pub fn window_rect_with_popups(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.bbox_with_popups();
    wgeo.loc += loc;
    wgeo
}

pub fn window_loc(window: &Window, space_id: &usize) -> Point<i32, Logical> {
    window
        .user_data()
        .get::<RefCell<HashMap<usize, WindowState>>>()
        .unwrap()
        .borrow()
        .get(space_id)
        .unwrap()
        .location
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Window
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.0.id
    }

    fn type_of(&self) -> TypeId {
        TypeId::of::<Window>()
    }

    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        window_loc(self, &space_id)
    }

    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical> {
        window_rect_with_popups(self, &space_id)
    }

    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        self.accumulated_damage(for_values)
    }

    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        let res = draw_window(renderer, frame, self, scale, location, damage, log);
        if res.is_ok() {
            window_state(space_id, self).drawn = true;
        }
        res
    }

    fn z_index(&self) -> u8 {
        RenderZindex::Top as u8
    }
}
<commit_msg>change default layer for Windows to Shell<commit_after>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{
        space::{Space, SpaceElement},
        window::{draw_window, Window},
    },
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::{
    any::TypeId,
    cell::{RefCell, RefMut},
    collections::HashMap,
};

use super::RenderZindex;

#[derive(Default)]
pub struct WindowState {
    pub location: Point<i32, Logical>,
    pub drawn: bool,
}

pub type WindowUserdata = RefCell<HashMap<usize, WindowState>>;
pub fn window_state(space: usize, w: &Window) -> RefMut<'_, WindowState> {
    let userdata = w.user_data();
    userdata.insert_if_missing(WindowUserdata::default);
    RefMut::map(userdata.get::<WindowUserdata>().unwrap().borrow_mut(), |m| {
        m.entry(space).or_default()
    })
}

pub fn window_geo(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.geometry();
    wgeo.loc = loc;
    wgeo
}

pub fn window_rect(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.bbox();
    wgeo.loc += loc;
    wgeo
}

pub fn window_rect_with_popups(window: &Window, space_id: &usize) -> Rectangle<i32, Logical> {
    let loc = window_loc(window, space_id);
    let mut wgeo = window.bbox_with_popups();
    wgeo.loc += loc;
    wgeo
}

pub fn window_loc(window: &Window, space_id: &usize) -> Point<i32, Logical> {
    window
        .user_data()
        .get::<RefCell<HashMap<usize, WindowState>>>()
        .unwrap()
        .borrow()
        .get(space_id)
        .unwrap()
        .location
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for Window
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.0.id
    }

    fn type_of(&self) -> TypeId {
        TypeId::of::<Window>()
    }

    fn location(&self, space_id: usize) -> Point<i32, Logical> {
        window_loc(self, &space_id)
    }

    fn geometry(&self, space_id: usize) -> Rectangle<i32, Logical> {
        window_rect_with_popups(self, &space_id)
    }

    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        self.accumulated_damage(for_values)
    }

    fn draw(
        &self,
        space_id: usize,
        renderer: &mut R,
        frame: &mut F,
        scale: f64,
        location: Point<i32, Logical>,
        damage: &[Rectangle<i32, Logical>],
        log: &slog::Logger,
    ) -> Result<(), R::Error> {
        let res = draw_window(renderer, frame, self, scale, location, damage, log);
        if res.is_ok() {
            window_state(space_id, self).drawn = true;
        }
        res
    }

    fn z_index(&self) -> u8 {
        RenderZindex::Shell as u8
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::io::Result as IoResult;
use std::result::Result;
use std::iter::{Iterator, IntoIterator};
use std::collections::HashMap;
use std::collections::hash_map;
use std::vec::Vec;
use std::cmp::{Eq, PartialEq};
use std::hash::{Hash, Hasher};
use std::convert::From;

pub type Pixels = usize;
pub type FileName = String;
pub type FilePath = String;

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum ResolutionUnits {
    PixelsPerInch,
    PixelsPerCentimeter,
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Direction {
    Horizontal,
    Vertical,
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum ImageFileFormat {
    TIFF,
    PNG,
    JPEG,
    UNKNOWN,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageDimensions {
    x_pixels: Pixels,
    y_pixels: Pixels,
}

impl ImageDimensions {
    fn new(x: Pixels, y: Pixels) -> ImageDimensions {
        ImageDimensions {
            x_pixels: x,
            y_pixels: y,
        }
    }
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct ImageResolution {
    amount: Pixels,
    units: ResolutionUnits,
}

impl ImageResolution {
    fn new(amount: usize, units: ResolutionUnits) -> ImageResolution {
        ImageResolution {
            amount: amount,
            units: units,
        }
    }
}

#[derive(Clone)]
pub enum PageOps {
    Identify(FileName, FilePath),
    Rescale(Pixels, Direction),
    ExpandLeftEdge(Pixels),
    ExpandRightEdge(Pixels),
    ExpandTopEdge(Pixels),
    ExpandBottomEdge(Pixels),
    TrimLeftEdge(Pixels),
    TrimRightEdge(Pixels),
    TrimTopEdge(Pixels),
    TrimBottomEdge(Pixels),
    SetResolution(ImageResolution),
}

pub trait ElementaryPageOperations {
    fn identify(file_name: FileName, path: FilePath) -> Self;
    fn rescale(amount: Pixels, dir: Direction)       -> Self;
    fn expand_left_edge(amount: Pixels)              -> Self;
    fn expand_right_edge(amount: Pixels)             -> Self;
    fn expand_top_edge(amount: Pixels)               -> Self;
    fn expand_bottom_edge(amount: Pixels)            -> Self;
    fn trim_left_edge(amount: Pixels)                -> Self;
    fn trim_right_edge(amount: Pixels)               -> Self;
    fn trim_top_edge(amount: Pixels)                 -> Self;
    fn trim_bottom_edge(amount: Pixels)              -> Self;
    fn set_resolution(res: ImageResolution)          -> Self;
}

pub trait RunOperation {
    fn run_operation(op: Self) -> OperationResults;
}

trait CompileOperation<OpType, Op> where Op: ElementaryPageOperations {
    fn compile_operation(op: OpType) -> Op;
}

impl<Op> CompileOperation<PageOps, Op> for Op where Op: ElementaryPageOperations {
    fn compile_operation(op: PageOps) -> Op {
        match op {
            PageOps::Identify(file, path)     => Op::identify(file, path),
            PageOps::Rescale(amount, dir)     => Op::rescale(amount, dir),
            PageOps::ExpandLeftEdge(amount)   => Op::expand_left_edge(amount),
            PageOps::ExpandRightEdge(amount)  => Op::expand_right_edge(amount),
            PageOps::ExpandTopEdge(amount)    => Op::expand_top_edge(amount),
            PageOps::ExpandBottomEdge(amount) => Op::expand_bottom_edge(amount),
            PageOps::TrimLeftEdge(amount)     => Op::trim_left_edge(amount),
            PageOps::TrimRightEdge(amount)    => Op::trim_right_edge(amount),
            PageOps::TrimTopEdge(amount)      => Op::trim_top_edge(amount),
            PageOps::TrimBottomEdge(amount)   => Op::trim_bottom_edge(amount),
            PageOps::SetResolution(res)       => Op::set_resolution(res),
        }
    }
}

#[derive(Clone)]
struct CompoundPageOperation {
    page_name: FileName,
    page_path: FilePath,
    ops: Option<Vec<PageOps>>,
}

impl CompoundPageOperation {
    fn new(page_name: FileName, page_path: FilePath, ops: &[PageOps]) -> CompoundPageOperation {

        if ops.is_empty() {
            return CompoundPageOperation {
                page_name: page_name,
                page_path: page_path,
                ops: None,
            };
        }

        let mut vec = Vec::new();
        for op in ops.iter() {
            vec.push(op.clone());
        }

        CompoundPageOperation {
            page_name: page_name,
            page_path: page_path,
            ops: Some(vec),
        }
    }

    fn make_noop() -> CompoundPageOperation {
        CompoundPageOperation {
            page_name: String::from(""),
            page_path: String::from(""),
            ops: None,
        }
    }

    fn is_noop(&self) -> bool {
        match self.ops {
            Some(ref vec) => vec.is_empty(),
            None          => true,
        }
    }

    fn run_operation<Op>(&self) -> OperationResults
        where Op: ElementaryPageOperations + RunOperation + CompileOperation<PageOps, Op> {

        match self.ops {
            None      => {
                OperationResults::from(Ok(String::from("No Operation")))
            }
            Some(ref vec) => {
                if self.is_noop() {
                    // Should not happen.
                    unreachable!();
                    //return Ok(String::from("No Operation"));
                }

                let mut result = Ok(String::from(""));
                for op in vec.iter() {
                    let op_results = Op::run_operation(Op::compile_operation(op.clone()));
                    for res in op_results.results {
                        match res {
                            Ok(s) => {
                                continue;
                            }
                            Err(e) => {
                                // Fail fast if there is an error.
                                result = Err(e);
                                break;
                            }
                        }
                    }
                }

                OperationResults::from(result)
            }
        }
    }

}

#[derive(Clone, Eq)]
struct Page {
    file_name: FileName,
    file_extension: ImageFileFormat,
    file_path: FilePath,
    dimensions: ImageDimensions,
    resolution: ImageResolution,
}

impl Page {
    fn new  (
            file_name: FileName,
            file_extension: ImageFileFormat,
            file_path: FilePath,
            dimensions: ImageDimensions,
            resolution: ImageResolution
            ) -> Page
    {
        Page {
            file_name: file_name,
            file_extension: file_extension,
            file_path: file_path,
            dimensions: dimensions,
            resolution: resolution,
        }
    }
}

impl PartialEq for Page {
    fn eq(&self, other: &Page) -> bool {
            self.file_name      == other.file_name
        &&  self.file_extension == other.file_extension
        &&  self.file_path      == other.file_path
        &&  self.dimensions     == other.dimensions
        &&  self.resolution     == other.resolution
    }
}

impl Hash for Page {
    fn hash<H>(&self, state: &mut H) where H: Hasher {

        self.file_name.hash(state);
        self.file_extension.hash(state);
        self.file_path.hash(state);
        self.dimensions.hash(state);
        self.resolution.hash(state);
    }
}

pub type OperationResult = IoResult<String>;

pub struct OperationResults {
    results: Vec<OperationResult>,
}

impl OperationResults {
    pub fn new() -> OperationResults {
        OperationResults {
            results: Vec::new(),
        }
    }

    pub fn push(&mut self, result: OperationResult) {
        self.results.push(result);
    }

    pub fn append(&mut self, other: &mut OperationResults) {
        self.results.append(&mut other.results);
    }

}

impl From<Vec<OperationResult>> for OperationResults {
    fn from(vec: Vec<OperationResult>) -> OperationResults {
        unimplemented!();
    }
}

/// Destructive conversion from a mutable vector of OperationResult
/// to simplify the process of returning results from running operations.
impl<'a> From<&'a mut Vec<OperationResult>> for OperationResults {
    fn from(vec: &mut Vec<OperationResult>) -> OperationResults {
        let mut results = Vec::new();
        results.append(vec);

        OperationResults {
            results: results,
        }
    }
}

/// Generates an OperationResults struct from a single OperationResult.
/// For compatibility between operations that may return multiple results
/// and ones that may return only one result.
impl From<OperationResult> for OperationResults {
    fn from(op_res: OperationResult) -> OperationResults {
        let mut results = Vec::new();
        results.push(op_res);

        OperationResults {
            results: results
        }
    }
}

struct OperationPlan {
    schedule: HashMap<Page, CompoundPageOperation>,
}

#[derive(Clone, Eq, PartialEq)]
enum OperationScheduleError {
    LengthMismatch,
}

impl OperationPlan {
    fn new() -> OperationPlan {
        OperationPlan {
            schedule: HashMap::new(),
        }
    }

    fn add_operation(&mut self, page: Page, op: CompoundPageOperation) {
        self.schedule.insert(page, op);
    }

    fn build_schedule(pages: &[Page], ops: &[CompoundPageOperation]) -> Result<Self, OperationScheduleError> {
        if pages.len() == ops.len() {

            let mut schedule = OperationPlan::new();

            for page_number in 0..pages.len() {
                schedule.add_operation(pages[page_number].clone(), ops[page_number].clone());
            }

            Ok(schedule)

        } else {
            Err(OperationScheduleError::LengthMismatch)
        }

    }

    fn iter(&self) -> OpPlanIter {
        OpPlanIter {
            inner: self.schedule.iter()
        }
    }

    fn run_operation<Op>(&self) -> OperationResults
        where Op: ElementaryPageOperations + RunOperation + CompileOperation<PageOps, Op> {

        let mut results = OperationResults::new();

        for (page, op) in self {

            match op.ops {
                None => {
                    continue;
                }
                Some(ref operations) => {
                    for elem_op in operations {
                        let compiled_op = Op::compile_operation(elem_op.clone());
                        let mut result = Op::run_operation(compiled_op);
                        results.append(&mut result);
                    }
                }
            }

        }

        results
    }
}

struct OpPlanIter<'a> {
    inner:  hash_map::Iter<'a, Page, CompoundPageOperation>
}

impl<'a> Iterator for OpPlanIter<'a> {
    type Item = (&'a Page, &'a CompoundPageOperation);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }

}

impl<'a> IntoIterator for &'a OperationPlan {
    type Item = (&'a Page, &'a CompoundPageOperation);
    type IntoIter = OpPlanIter<'a>;

    fn into_iter(self) -> OpPlanIter<'a> {
        self.iter()
    }
}

struct OpPlanIntoIter {
    inner: hash_map::IntoIter<Page, CompoundPageOperation>,
}

impl IntoIterator for OperationPlan {
    type Item = (Page, CompoundPageOperation);
    type IntoIter = OpPlanIntoIter;

    fn into_iter(self) -> OpPlanIntoIter {
        OpPlanIntoIter {
            inner: self.schedule.into_iter()
        }
    }
}

impl Iterator for OpPlanIntoIter {
    type Item = (Page, CompoundPageOperation);

    fn next(&mut self) -> Option<(Page, CompoundPageOperation)> {
        self.inner.next()
    }
}
<commit_msg>Add Result type for OperationPlan. Write iterators for it.<commit_after>#![allow(dead_code)]
use std::io::Result as IoResult;
use std::result::Result;
use std::iter::{Iterator, IntoIterator};
use std::collections::HashMap;
use std::collections::hash_map;
use std::vec::Vec;
use std::cmp::{Eq, PartialEq};
use std::hash::{Hash, Hasher};
use std::convert::From;

pub type Pixels = usize;
pub type FileName = String;
pub type FilePath = String;

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum ResolutionUnits {
    PixelsPerInch,
    PixelsPerCentimeter,
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Direction {
    Horizontal,
    Vertical,
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum ImageFileFormat {
    TIFF,
    PNG,
    JPEG,
    UNKNOWN,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageDimensions {
    x_pixels: Pixels,
    y_pixels: Pixels,
}

impl ImageDimensions {
    fn new(x: Pixels, y: Pixels) -> ImageDimensions {
        ImageDimensions {
            x_pixels: x,
            y_pixels: y,
        }
    }
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct ImageResolution {
    amount: Pixels,
    units: ResolutionUnits,
}

impl ImageResolution {
    fn new(amount: usize, units: ResolutionUnits) -> ImageResolution {
        ImageResolution {
            amount: amount,
            units: units,
        }
    }
}

#[derive(Clone)]
pub enum PageOps {
    Identify(FileName, FilePath),
    Rescale(Pixels, Direction),
    ExpandLeftEdge(Pixels),
    ExpandRightEdge(Pixels),
    ExpandTopEdge(Pixels),
    ExpandBottomEdge(Pixels),
    TrimLeftEdge(Pixels),
    TrimRightEdge(Pixels),
    TrimTopEdge(Pixels),
    TrimBottomEdge(Pixels),
    SetResolution(ImageResolution),
}

pub trait ElementaryPageOperations {
    fn identify(file_name: FileName, path: FilePath) -> Self;
    fn rescale(amount: Pixels, dir: Direction)       -> Self;
    fn expand_left_edge(amount: Pixels)              -> Self;
    fn expand_right_edge(amount: Pixels)             -> Self;
    fn expand_top_edge(amount: Pixels)               -> Self;
    fn expand_bottom_edge(amount: Pixels)            -> Self;
    fn trim_left_edge(amount: Pixels)                -> Self;
    fn trim_right_edge(amount: Pixels)               -> Self;
    fn trim_top_edge(amount: Pixels)                 -> Self;
    fn trim_bottom_edge(amount: Pixels)              -> Self;
    fn set_resolution(res: ImageResolution)          -> Self;
}

pub trait RunOperation {
    fn run_operation(op: Self) -> OperationResults;
}

trait CompileOperation<OpType, Op> where Op: ElementaryPageOperations {
    fn compile_operation(op: OpType) -> Op;
}

impl<Op> CompileOperation<PageOps, Op> for Op where Op: ElementaryPageOperations {
    fn compile_operation(op: PageOps) -> Op {
        match op {
            PageOps::Identify(file, path)     => Op::identify(file, path),
            PageOps::Rescale(amount, dir)     => Op::rescale(amount, dir),
            PageOps::ExpandLeftEdge(amount)   => Op::expand_left_edge(amount),
            PageOps::ExpandRightEdge(amount)  => Op::expand_right_edge(amount),
            PageOps::ExpandTopEdge(amount)    => Op::expand_top_edge(amount),
            PageOps::ExpandBottomEdge(amount) => Op::expand_bottom_edge(amount),
            PageOps::TrimLeftEdge(amount)     => Op::trim_left_edge(amount),
            PageOps::TrimRightEdge(amount)    => Op::trim_right_edge(amount),
            PageOps::TrimTopEdge(amount)      => Op::trim_top_edge(amount),
            PageOps::TrimBottomEdge(amount)   => Op::trim_bottom_edge(amount),
            PageOps::SetResolution(res)       => Op::set_resolution(res),
        }
    }
}

#[derive(Clone)]
struct CompoundPageOperation {
    page_name: FileName,
    page_path: FilePath,
    ops: Option<Vec<PageOps>>,
}

impl CompoundPageOperation {
    fn new(page_name: FileName, page_path: FilePath, ops: &[PageOps]) -> CompoundPageOperation {

        if ops.is_empty() {
            return CompoundPageOperation {
                page_name: page_name,
                page_path: page_path,
                ops: None,
            };
        }

        let mut vec = Vec::new();
        for op in ops.iter() {
            vec.push(op.clone());
        }

        CompoundPageOperation {
            page_name: page_name,
            page_path: page_path,
            ops: Some(vec),
        }
    }

    fn make_noop() -> CompoundPageOperation {
        CompoundPageOperation {
            page_name: String::from(""),
            page_path: String::from(""),
            ops: None,
        }
    }

    fn is_noop(&self) -> bool {
        match self.ops {
            Some(ref vec) => vec.is_empty(),
            None          => true,
        }
    }

    fn run_operation<Op>(&self) -> OperationResults
        where Op: ElementaryPageOperations + RunOperation + CompileOperation<PageOps, Op> {

        match self.ops {
            None      => {
                OperationResults::from(Ok(String::from("No Operation")))
            }
            Some(ref vec) => {
                if self.is_noop() {
                    // Should not happen.
                    unreachable!();
                    //return Ok(String::from("No Operation"));
                }

                let mut result = Ok(String::from(""));
                for op in vec.iter() {
                    let op_results = Op::run_operation(Op::compile_operation(op.clone()));
                    for res in op_results.results {
                        match res {
                            Ok(s) => {
                                continue;
                            }
                            Err(e) => {
                                // Fail fast if there is an error.
                                result = Err(e);
                                break;
                            }
                        }
                    }
                }

                OperationResults::from(result)
            }
        }
    }

}

#[derive(Clone, Eq)]
struct Page {
    file_name: FileName,
    file_extension: ImageFileFormat,
    file_path: FilePath,
    dimensions: ImageDimensions,
    resolution: ImageResolution,
}

impl Page {
    fn new  (
            file_name: FileName,
            file_extension: ImageFileFormat,
            file_path: FilePath,
            dimensions: ImageDimensions,
            resolution: ImageResolution
            ) -> Page
    {
        Page {
            file_name: file_name,
            file_extension: file_extension,
            file_path: file_path,
            dimensions: dimensions,
            resolution: resolution,
        }
    }
}

impl PartialEq for Page {
    fn eq(&self, other: &Page) -> bool {
            self.file_name      == other.file_name
        &&  self.file_extension == other.file_extension
        &&  self.file_path      == other.file_path
        &&  self.dimensions     == other.dimensions
        &&  self.resolution     == other.resolution
    }
}

impl Hash for Page {
    fn hash<H>(&self, state: &mut H) where H: Hasher {

        self.file_name.hash(state);
        self.file_extension.hash(state);
        self.file_path.hash(state);
        self.dimensions.hash(state);
        self.resolution.hash(state);
    }
}

pub type OperationResult = IoResult<String>;

pub struct OperationResults {
    results: Vec<OperationResult>,
}

impl OperationResults {
    pub fn new() -> OperationResults {
        OperationResults {
            results: Vec::new(),
        }
    }

    pub fn push(&mut self, result: OperationResult) {
        self.results.push(result);
    }

    pub fn append(&mut self, other: &mut OperationResults) {
        self.results.append(&mut other.results);
    }

}

impl From<Vec<OperationResult>> for OperationResults {
    fn from(vec: Vec<OperationResult>) -> OperationResults {
        unimplemented!();
    }
}

/// Destructive conversion from a mutable vector of OperationResult
/// to simplify the process of returning results from running operations.
impl<'a> From<&'a mut Vec<OperationResult>> for OperationResults {
    fn from(vec: &mut Vec<OperationResult>) -> OperationResults {
        let mut results = Vec::new();
        results.append(vec);

        OperationResults {
            results: results,
        }
    }
}

/// Generates an OperationResults struct from a single OperationResult.
/// For compatibility between operations that may return multiple results
/// and ones that may return only one result.
impl From<OperationResult> for OperationResults {
    fn from(op_res: OperationResult) -> OperationResults {
        let mut results = Vec::new();
        results.push(op_res);

        OperationResults {
            results: results
        }
    }
}

struct OperationPlan {
    schedule: HashMap<Page, CompoundPageOperation>,
}

#[derive(Clone, Eq, PartialEq)]
enum OperationScheduleError {
    LengthMismatch,
}

impl OperationPlan {
    fn new() -> OperationPlan {
        OperationPlan {
            schedule: HashMap::new(),
        }
    }

    fn add_operation(&mut self, page: Page, op: CompoundPageOperation) {
        self.schedule.insert(page, op);
    }

    fn build_schedule(pages: &[Page], ops: &[CompoundPageOperation]) -> Result<Self, OperationScheduleError> {
        if pages.len() == ops.len() {

            let mut schedule = OperationPlan::new();

            for page_number in 0..pages.len() {
                schedule.add_operation(pages[page_number].clone(), ops[page_number].clone());
            }

            Ok(schedule)

        } else {
            Err(OperationScheduleError::LengthMismatch)
        }

    }

    fn iter(&self) -> OpPlanIter {
        OpPlanIter {
            inner: self.schedule.iter()
        }
    }

    fn run_operation<Op>(&self) -> OperationResults
        where Op: ElementaryPageOperations + RunOperation + CompileOperation<PageOps, Op> {

        let mut results = OperationResults::new();

        for (page, op) in self {

            match op.ops {
                None => {
                    continue;
                }
                Some(ref operations) => {
                    for elem_op in operations {
                        let compiled_op = Op::compile_operation(elem_op.clone());
                        let mut result = Op::run_operation(compiled_op);
                        results.append(&mut result);
                    }
                }
            }

        }

        results
    }
}

/// Iterator implementation for OperationPlan.
struct OpPlanIter<'a> {
    inner:  hash_map::Iter<'a, Page, CompoundPageOperation>
}

impl<'a> Iterator for OpPlanIter<'a> {
    type Item = (&'a Page, &'a CompoundPageOperation);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }

}

/// IntoIterator implementation for OperationPlan.
impl<'a> IntoIterator for &'a OperationPlan {
    type Item = (&'a Page, &'a CompoundPageOperation);
    type IntoIter = OpPlanIter<'a>;

    fn into_iter(self) -> OpPlanIter<'a> {
        self.iter()
    }
}

struct OpPlanIntoIter {
    inner: hash_map::IntoIter<Page, CompoundPageOperation>,
}

impl IntoIterator for OperationPlan {
    type Item = (Page, CompoundPageOperation);
    type IntoIter = OpPlanIntoIter;

    fn into_iter(self) -> OpPlanIntoIter {
        OpPlanIntoIter {
            inner: self.schedule.into_iter()
        }
    }
}

impl Iterator for OpPlanIntoIter {
    type Item = (Page, CompoundPageOperation);

    fn next(&mut self) -> Option<(Page, CompoundPageOperation)> {
        self.inner.next()
    }
}

struct OperationPlanResult {
    results: HashMap<Page, OperationResults>,
}

impl OperationPlanResult {
    fn new() -> OperationPlanResult {
        OperationPlanResult {
            results: HashMap::new(),
        }
    }

    fn insert(&mut self, page: Page, res: OperationResults) {
        self.results.insert(page, res);
    }

    fn iter(&self) -> OpPlanResultIter {
        OpPlanResultIter {
            inner: self.results.iter()
        }
    }
}

struct OpPlanResultIter<'a> {
    inner: hash_map::Iter<'a, Page, OperationResults>,
}

impl<'a> Iterator for OpPlanResultIter<'a> {
    type Item = (&'a Page, &'a OperationResults);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

/// IntoIterator implementation for OpPlanResultIter.
impl<'a> IntoIterator for &'a OperationPlanResult {
    type Item = (&'a Page, &'a OperationResults);
    type IntoIter = OpPlanResultIter<'a>;

    fn into_iter(self) -> OpPlanResultIter<'a> {
        self.iter()
    }
}

struct OpPlanResultIntoIter {
    inner: hash_map::IntoIter<Page, OperationResults>,
}

impl IntoIterator for OperationPlanResult {
    type Item = (Page, OperationResults);
    type IntoIter = OpPlanResultIntoIter;

    fn into_iter(self) -> OpPlanResultIntoIter {
        OpPlanResultIntoIter {
            inner: self.results.into_iter()
        }
    }
}

impl Iterator for OpPlanResultIntoIter {
    type Item = (Page, OperationResults);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}
<|endoftext|>


<commit_before>// Submitted by jess 3jane

extern crate rand;

use std::f64::consts::PI;

fn in_circle(x: f64, y: f64, radius: f64) -> bool {
    x * x + y * y < radius * radius
}

fn monte_carlo(n: i64) -> f64 {
    let mut count = 0;

    for _ in 0..n {
        let x = rand::random();
        let y = rand::random();
        if in_circle(x, y, 1.0) {
            count += 1;
        }
    }

    // return our pi estimate
    (4 * count) as f64 / n as f64
}

fn main() {
    let pi_estimate = monte_carlo(10000000);

    println!("Percent error is {:.3}%", (100.0 * (PI - pi_estimate) / PI));
}
<commit_msg>Fixing percent error in monte_carlo.rs (#381)<commit_after>// Submitted by jess 3jane

extern crate rand;

use std::f64::consts::PI;

fn in_circle(x: f64, y: f64, radius: f64) -> bool {
    x * x + y * y < radius * radius
}

fn monte_carlo(n: i64) -> f64 {
    let mut count = 0;

    for _ in 0..n {
        let x = rand::random();
        let y = rand::random();
        if in_circle(x, y, 1.0) {
            count += 1;
        }
    }

    // return our pi estimate
    (4 * count) as f64 / n as f64
}

fn main() {
    let pi_estimate = monte_carlo(10000000);

    println!("Percent error is {:.3}%", (100.0 * (pi_estimate - PI).abs() / PI));
}
<|endoftext|>


<commit_before><commit_msg>[dx11] Increase max bound descriptor set count<commit_after><|endoftext|>


<commit_before>use command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (lib and bin targets by default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"]),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .after_help(
            "\
This Cargo subcommmand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --prepare-for 2018

Note that this is not guaranteed to fix all your code as it only fixes code that
`cargo check` would otherwise compile. For example unit tests are left out
from this command, but they can be checked with:

    cargo fix --prepare-for 2018 --all-targets

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --prepare-for 2018 --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --prepare-for 2018 --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode)?;
    match opts.filter {
        CompileFilter::Default { .. } => {
            opts.filter = CompileFilter::Only {
                all_targets: true,
                lib: true,
                bins: FilterRule::All,
                examples: FilterRule::All,
                benches: FilterRule::All,
                tests: FilterRule::All,
            };
        }
        _ => {}
    }
    ops::fix(&ws, &mut ops::FixOptions {
        edition: args.value_of("edition"),
        compile_opts: opts,
        allow_dirty: args.is_present("allow-dirty"),
        allow_no_vcs: args.is_present("allow-no-vcs"),
        broken_code: args.is_present("broken-code"),
    })?;
    Ok(())
}
<commit_msg>Resolve a single_match lint warning<commit_after>use command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (lib and bin targets by default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"]),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .after_help(
            "\
This Cargo subcommmand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --prepare-for 2018

Note that this is not guaranteed to fix all your code as it only fixes code that
`cargo check` would otherwise compile. For example unit tests are left out
from this command, but they can be checked with:

    cargo fix --prepare-for 2018 --all-targets

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --prepare-for 2018 --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --prepare-for 2018 --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode)?;
    if let CompileFilter::Default { .. } = opts.filter {
        opts.filter = CompileFilter::Only {
            all_targets: true,
            lib: true,
            bins: FilterRule::All,
            examples: FilterRule::All,
            benches: FilterRule::All,
            tests: FilterRule::All,
        }
    }
    ops::fix(&ws, &mut ops::FixOptions {
        edition: args.value_of("edition"),
        compile_opts: opts,
        allow_dirty: args.is_present("allow-dirty"),
        allow_no_vcs: args.is_present("allow-no-vcs"),
        broken_code: args.is_present("broken-code"),
    })?;
    Ok(())
}
<|endoftext|>