<commit_before>use chrono::{DateTime, TimeZone, Utc};
use failure::{Error, ResultExt};
use std::ffi::OsStr;
use std::fmt;
use std::fs::{self, File};
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use tar::Archive;
use xz2::bufread::XzDecoder;

#[derive(Debug, Clone)]
struct Commit {
    sha: String,
    date: DateTime<Utc>,
}

pub struct Sysroot {
    pub sha: String,
    pub rustc: PathBuf,
    pub rustdoc: PathBuf,
    pub cargo: PathBuf,
    pub triple: String,
}

impl Sysroot {
    pub fn install(sha: &str, date: DateTime<Utc>, triple: &str) -> Result<Self, Error> {
        let commit = Commit {
            sha: sha.to_owned(),
            date,
        };
        let unpack_into = "cache";
        // Versions of rustc older than Mar 20 have bugs in their cargo.
        let download_cargo = commit.date >= Utc.ymd(2017, 3, 20).and_hms(0, 0, 0);

        fs::create_dir_all(&unpack_into)?;

        let download = SysrootDownload {
            directory: unpack_into.into(),
            rust_sha: commit.sha.clone(),
            triple: triple.to_owned(),
        };

        download.get_and_extract(ModuleVariant::Rustc)?;
        download.get_and_extract(ModuleVariant::Std)?;
        if download_cargo {
            download.get_and_extract(ModuleVariant::Cargo)?;
        }

        download.into_sysroot(download_cargo)
    }
}

impl Drop for Sysroot {
    fn drop(&mut self) {
        fs::remove_dir_all(format!("cache/{}", self.sha)).unwrap_or_else(|err| {
            log::info!(
                "failed to remove {:?}, please do so manually: {:?}",
                format!("cache/{}", self.sha),
                err
            );
        });
    }
}

#[derive(Debug, Clone)]
struct SysrootDownload {
    directory: PathBuf,
    rust_sha: String,
    triple: String,
}

const MODULE_URLS: &[&str] = &[
    "https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rustc-builds/@SHA@/@MODULE@-nightly-@TRIPLE@.tar.xz",
    "https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rustc-builds-try/@SHA@/@MODULE@-nightly-@TRIPLE@.tar.xz",
];

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ModuleVariant {
    Cargo,
    Rustc,
    Std,
}

impl fmt::Display for ModuleVariant {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ModuleVariant::Cargo => write!(f, "cargo"),
            ModuleVariant::Rustc => write!(f, "rustc"),
            ModuleVariant::Std => write!(f, "rust-std"),
        }
    }
}

impl ModuleVariant {
    fn urls(&self, sysroot: &SysrootDownload, triple: &str) -> Vec<String> {
        MODULE_URLS
            .iter()
            .map(|url| {
                url.replace("@MODULE@", &self.to_string())
                    .replace("@SHA@", &sysroot.rust_sha)
                    .replace("@TRIPLE@", triple)
            })
            .collect()
    }
}

impl SysrootDownload {
    fn into_sysroot(self, used_fallback_cargo: bool) -> Result<Sysroot, Error> {
        Ok(Sysroot {
            rustc: self
                .directory
                .join(&self.rust_sha)
                .join("rustc/bin/rustc")
                .canonicalize()
                .with_context(|_| {
                    format!("failed to canonicalize rustc path for {}", self.rust_sha)
                })?,
            rustdoc: self
                .directory
                .join(&self.rust_sha)
                .join("rustc/bin/rustdoc")
                .canonicalize()
                .with_context(|_| {
                    format!("failed to canonicalize rustdoc path for {}", self.rust_sha)
                })?,
            cargo: if used_fallback_cargo {
                // go with cargo present in environment if we need to fallback
                PathBuf::from("cargo")
            } else {
                self.directory
                    .join(&self.rust_sha)
                    .join("cargo/bin/cargo")
                    .canonicalize()
                    .with_context(|_| {
                        format!("failed to canonicalize cargo path for {}", self.rust_sha)
                    })?
            },
            sha: self.rust_sha,
            triple: self.triple,
        })
    }

    fn get_and_extract(&self, variant: ModuleVariant) -> Result<(), Error> {
        let archive_path = self.directory.join(format!(
            "{}-{}-{}.tar.xz",
            self.rust_sha, self.triple, variant,
        ));
        if archive_path.exists() {
            let reader = BufReader::new(File::open(&archive_path)?);
            let decompress = XzDecoder::new(reader);
            let extract = self.extract(variant, decompress);
            match extract {
                Ok(()) => return Ok(()),
                Err(err) => {
                    log::warn!("extracting {} failed: {:?}", archive_path.display(), err);
                    fs::remove_file(&archive_path)?;
                }
            }
        }

        for url in variant.urls(self, &self.triple) {
            log::debug!("requesting: {}", url);
            let resp = reqwest::get(&url)?;
            log::debug!("{}", resp.status());
            let reader = if resp.status().is_success() {
                XzDecoder::new(BufReader::new(resp))
            } else {
                continue;
            };
            match self.extract(variant, reader) {
                Ok(()) => return Ok(()),
                Err(err) => {
                    log::warn!("extracting {} failed: {:?}", url, err);
                    continue;
                }
            }
        }

        failure::bail!(
            "unable to download sha {} triple {} module {}",
            self.rust_sha,
            self.triple,
            variant
        );
    }

    fn extract<T: Read>(&self, variant: ModuleVariant, reader: T) -> Result<(), Error> {
        let is_std = variant == ModuleVariant::Std;
        let mut archive = Archive::new(reader);
        let std_prefix = format!("rust-std-{}/lib/rustlib", self.triple);

        let mut to_link = Vec::new();

        let unpack_into = self.directory.join(&self.rust_sha);

        for entry in archive.entries()? {
            let mut entry = entry?;
            let path = entry.path()?.into_owned();
            let mut components = path.components();
            assert!(components.next().is_some(), "strip container directory");
            let path = components.as_path();

            let path = if is_std {
                if let Ok(path) = path.strip_prefix(&std_prefix) {
                    if path.extension() == Some(OsStr::new("dylib")) {
                        to_link.push(path.to_owned());
                        continue;
                    } else {
                        Path::new("rustc/lib/rustlib").join(path)
                    }
                } else {
                    continue;
                }
            } else {
                path.into()
            };
            let path = unpack_into.join(path);
            fs::create_dir_all(&path.parent().unwrap()).with_context(|_| {
                format!(
                    "could not create intermediate directories for {}",
                    path.display()
                )
            })?;
            entry.unpack(path)?;
        }

        let link_dst_prefix = unpack_into.join(format!("rustc/lib/rustlib/{}/lib", self.triple));
        let link_src_prefix = format!("{}/lib", self.triple);
        for path in to_link {
            let src = unpack_into.join("rustc/lib").join(
                path.strip_prefix(&link_src_prefix)
                    .with_context(|_| format!("stripping prefix from: {:?}", path))?,
            );
            let dst = link_dst_prefix.join(&path);
            fs::create_dir_all(&dst.parent().unwrap()).with_context(|_| {
                format!(
                    "could not create intermediate directories for {}",
                    dst.display()
                )
            })?;
            log::trace!("linking {} to {}", src.display(), dst.display());
            fs::hard_link(src, dst)?;
        }

        Ok(())
    }
}
<commit_msg>Print out path when failing to canonicalize<commit_after>use chrono::{DateTime, TimeZone, Utc};
use failure::{Error, ResultExt};
use std::ffi::OsStr;
use std::fmt;
use std::fs::{self, File};
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use tar::Archive;
use xz2::bufread::XzDecoder;

#[derive(Debug, Clone)]
struct Commit {
    sha: String,
    date: DateTime<Utc>,
}

pub struct Sysroot {
    pub sha: String,
    pub rustc: PathBuf,
    pub rustdoc: PathBuf,
    pub cargo: PathBuf,
    pub triple: String,
}

impl Sysroot {
    pub fn install(sha: &str, date: DateTime<Utc>, triple: &str) -> Result<Self, Error> {
        let commit = Commit {
            sha: sha.to_owned(),
            date,
        };
        let unpack_into = "cache";
        // Versions of rustc older than Mar 20 have bugs in their cargo.
        let download_cargo = commit.date >= Utc.ymd(2017, 3, 20).and_hms(0, 0, 0);

        fs::create_dir_all(&unpack_into)?;

        let download = SysrootDownload {
            directory: unpack_into.into(),
            rust_sha: commit.sha.clone(),
            triple: triple.to_owned(),
        };

        download.get_and_extract(ModuleVariant::Rustc)?;
        download.get_and_extract(ModuleVariant::Std)?;
        if download_cargo {
            download.get_and_extract(ModuleVariant::Cargo)?;
        }

        download.into_sysroot(download_cargo)
    }
}

impl Drop for Sysroot {
    fn drop(&mut self) {
        fs::remove_dir_all(format!("cache/{}", self.sha)).unwrap_or_else(|err| {
            log::info!(
                "failed to remove {:?}, please do so manually: {:?}",
                format!("cache/{}", self.sha),
                err
            );
        });
    }
}

#[derive(Debug, Clone)]
struct SysrootDownload {
    directory: PathBuf,
    rust_sha: String,
    triple: String,
}

const MODULE_URLS: &[&str] = &[
    "https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rustc-builds/@SHA@/@MODULE@-nightly-@TRIPLE@.tar.xz",
    "https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rustc-builds-try/@SHA@/@MODULE@-nightly-@TRIPLE@.tar.xz",
];

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ModuleVariant {
    Cargo,
    Rustc,
    Std,
}

impl fmt::Display for ModuleVariant {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ModuleVariant::Cargo => write!(f, "cargo"),
            ModuleVariant::Rustc => write!(f, "rustc"),
            ModuleVariant::Std => write!(f, "rust-std"),
        }
    }
}

impl ModuleVariant {
    fn urls(&self, sysroot: &SysrootDownload, triple: &str) -> Vec<String> {
        MODULE_URLS
            .iter()
            .map(|url| {
                url.replace("@MODULE@", &self.to_string())
                    .replace("@SHA@", &sysroot.rust_sha)
                    .replace("@TRIPLE@", triple)
            })
            .collect()
    }
}

impl SysrootDownload {
    fn into_sysroot(self, used_fallback_cargo: bool) -> Result<Sysroot, Error> {
        Ok(Sysroot {
            rustc: self
                .directory
                .join(&self.rust_sha)
                .join("rustc/bin/rustc")
                .canonicalize()
                .with_context(|_| {
                    format!("failed to canonicalize rustc path for {}", self.rust_sha)
                })?,
            rustdoc: self
                .directory
                .join(&self.rust_sha)
                .join("rustc/bin/rustdoc")
                .canonicalize()
                .with_context(|_| {
                    format!("failed to canonicalize rustdoc path for {}", self.rust_sha)
                })?,
            cargo: if used_fallback_cargo {
                // go with cargo present in environment if we need to fallback
                PathBuf::from("cargo")
            } else {
                let path = self.directory.join(&self.rust_sha).join("cargo/bin/cargo");
                path.canonicalize().with_context(|_| {
                    format!(
                        "failed to canonicalize cargo path for {}: {:?}",
                        self.rust_sha, path
                    )
                })?
            },
            sha: self.rust_sha,
            triple: self.triple,
        })
    }

    fn get_and_extract(&self, variant: ModuleVariant) -> Result<(), Error> {
        let archive_path = self.directory.join(format!(
            "{}-{}-{}.tar.xz",
            self.rust_sha, self.triple, variant,
        ));
        if archive_path.exists() {
            let reader = BufReader::new(File::open(&archive_path)?);
            let decompress = XzDecoder::new(reader);
            let extract = self.extract(variant, decompress);
            match extract {
                Ok(()) => return Ok(()),
                Err(err) => {
                    log::warn!("extracting {} failed: {:?}", archive_path.display(), err);
                    fs::remove_file(&archive_path)?;
                }
            }
        }

        for url in variant.urls(self, &self.triple) {
            log::debug!("requesting: {}", url);
            let resp = reqwest::get(&url)?;
            log::debug!("{}", resp.status());
            let reader = if resp.status().is_success() {
                XzDecoder::new(BufReader::new(resp))
            } else {
                continue;
            };
            match self.extract(variant, reader) {
                Ok(()) => return Ok(()),
                Err(err) => {
                    log::warn!("extracting {} failed: {:?}", url, err);
                    continue;
                }
            }
        }

        failure::bail!(
            "unable to download sha {} triple {} module {}",
            self.rust_sha,
            self.triple,
            variant
        );
    }

    fn extract<T: Read>(&self, variant: ModuleVariant, reader: T) -> Result<(), Error> {
        let is_std = variant == ModuleVariant::Std;
        let mut archive = Archive::new(reader);
        let std_prefix = format!("rust-std-{}/lib/rustlib", self.triple);

        let mut to_link = Vec::new();

        let unpack_into = self.directory.join(&self.rust_sha);

        for entry in archive.entries()? {
            let mut entry = entry?;
            let path = entry.path()?.into_owned();
            let mut components = path.components();
            assert!(components.next().is_some(), "strip container directory");
            let path = components.as_path();

            let path = if is_std {
                if let Ok(path) = path.strip_prefix(&std_prefix) {
                    if path.extension() == Some(OsStr::new("dylib")) {
                        to_link.push(path.to_owned());
                        continue;
                    } else {
                        Path::new("rustc/lib/rustlib").join(path)
                    }
                } else {
                    continue;
                }
            } else {
                path.into()
            };
            let path = unpack_into.join(path);
            fs::create_dir_all(&path.parent().unwrap()).with_context(|_| {
                format!(
                    "could not create intermediate directories for {}",
                    path.display()
                )
            })?;
            entry.unpack(path)?;
        }

        let link_dst_prefix = unpack_into.join(format!("rustc/lib/rustlib/{}/lib", self.triple));
        let link_src_prefix = format!("{}/lib", self.triple);
        for path in to_link {
            let src = unpack_into.join("rustc/lib").join(
                path.strip_prefix(&link_src_prefix)
                    .with_context(|_| format!("stripping prefix from: {:?}", path))?,
            );
            let dst = link_dst_prefix.join(&path);
            fs::create_dir_all(&dst.parent().unwrap()).with_context(|_| {
                format!(
                    "could not create intermediate directories for {}",
                    dst.display()
                )
            })?;
            log::trace!("linking {} to {}", src.display(), dst.display());
            fs::hard_link(src, dst)?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error::Error;
use std::iter;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::DynamicState;
use command_buffer::pool::CommandPool;
use command_buffer::StatesManager;
use command_buffer::SubmitInfo;
use command_buffer::SubmitBuilder;
use command_buffer::Submit;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use descriptor::PipelineLayoutRef;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
use device::Device;
use device::Queue;
use framebuffer::traits::TrackedFramebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use image::Layout;
use image::TrackedImage;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::GraphicsPipeline;
use pipeline::vertex::Source;
use sync::Fence;
use vk;

pub use self::begin_render_pass::CmdBeginRenderPass;
pub use self::bind_index_buffer::CmdBindIndexBuffer;
pub use self::bind_descriptor_sets::{CmdBindDescriptorSets, CmdBindDescriptorSetsError};
pub use self::bind_pipeline::CmdBindPipeline;
pub use self::bind_vertex_buffers::CmdBindVertexBuffers;
pub use self::blit_image_unsynced::{BlitRegion, BlitRegionAspect};
pub use self::blit_image_unsynced::{CmdBlitImageUnsynced, CmdBlitImageUnsyncedError};
pub use self::copy_buffer::{CmdCopyBuffer, CmdCopyBufferError};
pub use self::dispatch::CmdDispatch;
pub use self::draw::CmdDraw;
pub use self::empty::{empty, EmptyCommandsList};
pub use self::end_render_pass::CmdEndRenderPass;
pub use self::fill_buffer::{CmdFillBuffer, CmdFillBufferError};
pub use self::next_subpass::CmdNextSubpass;
pub use self::push_constants::{CmdPushConstants, CmdPushConstantsError};
pub use self::set_state::{CmdSetState};
pub use self::update_buffer::{CmdUpdateBuffer, CmdUpdateBufferError};

mod begin_render_pass;
mod bind_descriptor_sets;
mod bind_index_buffer;
mod bind_pipeline;
mod bind_vertex_buffers;
mod blit_image_unsynced;
mod copy_buffer;
mod dispatch;
mod draw;
mod empty;
mod end_render_pass;
//pub mod execute;      // TODO: reenable when the concept of a command buffer is well defined
mod fill_buffer;
mod next_subpass;
mod push_constants;
mod set_state;
mod update_buffer;

/// A list of commands that can be turned into a command buffer.
///
/// This is just a naked list of commands. It stores buffers, images, etc. but the list of commands
/// itself is not a Vulkan object.
pub unsafe trait CommandsList {
    /// Adds a command that writes the content of a buffer.
    ///
    /// After this command is executed, the content of `buffer` will become `data`.
    #[inline]
    fn update_buffer<'a, B, D: ?Sized>(self, buffer: B, data: &'a D)
                                       -> Result<CmdUpdateBuffer<'a, Self, B, D>, CmdUpdateBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer, D: Copy + 'static
    {
        CmdUpdateBuffer::new(self, buffer, data)
    }

    /// Adds a command that copies the content of a buffer to another.
    #[inline]
    fn copy_buffer<S, D>(self, source: S, destination: D)
                         -> Result<CmdCopyBuffer<Self, S, D>, CmdCopyBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass,
              S: TrackedBuffer, D: TrackedBuffer
    {
        CmdCopyBuffer::new(self, source, destination)
    }

    /// Adds a command that writes the content of a buffer.
    #[inline]
    fn fill_buffer<B>(self, buffer: B, data: u32)
                      -> Result<CmdFillBuffer<Self, B>, CmdFillBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer
    {
        CmdFillBuffer::new(self, buffer, data)
    }

    // TODO: reenable
    /*/// Adds a command that executes a secondary command buffer.
    ///
    /// When you create a command buffer, you have the possibility to create either a primary
    /// command buffer or a secondary command buffer. Secondary command buffers can't be executed
    /// directly, but can be executed from a primary command buffer.
    ///
    /// A secondary command buffer can't execute another secondary command buffer. The only way
    /// you can use `execute` is to make a primary command buffer call a secondary command buffer.
    #[inline]
    fn execute<Cb>(self, command_buffer: Cb) -> execute::ExecuteCommand<Cb, Self>
        where Self: Sized, Cb: CommandsListOutput       /* FIXME: */
    {
        execute::ExecuteCommand::new(self, command_buffer)
    }*/

    /// Adds a command that executes a compute shader.
    ///
    /// The `dimensions` are the number of working groups to start. The GPU will execute the
    /// compute shader `dimensions[0] * dimensions[1] * dimensions[2]` times.
    ///
    /// The `pipeline` is the compute pipeline that will be executed, and the sets and push
    /// constants will be accessible to all the invocations.
    #[inline]
    fn dispatch<Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
                           dimensions: [u32; 3], push_constants: Pc)
                           -> CmdDispatch<Self, Pl, S, Pc>
        where Self: Sized + CommandsList, Pl: PipelineLayoutRef,
              S: TrackedDescriptorSetsCollection
    {
        CmdDispatch::new(self, pipeline, sets, dimensions, push_constants)
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass on the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C>(self, framebuffer: F, secondary: bool, clear_values: C)
                               -> CmdBeginRenderPass<Self, F::RenderPass, F>
        where Self: Sized, F: TrackedFramebuffer,
              F::RenderPass: RenderPass + RenderPassClearValues<C>
    {
        CmdBeginRenderPass::new(self, framebuffer, secondary, clear_values)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass(self, secondary: bool) -> CmdNextSubpass<Self>
        where Self: Sized
    {
        CmdNextSubpass::new(self, secondary)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass(self) -> CmdEndRenderPass<Self>
        where Self: Sized
    {
        CmdEndRenderPass::new(self)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<Pv, Pl, Prp, S, Pc, V>(self, pipeline: Arc<GraphicsPipeline<Pv, Pl, Prp>>,
                                   dynamic: DynamicState, vertices: V, sets: S,
                                   push_constants: Pc)
                                   -> CmdDraw<Self, V, Pv, Pl, Prp, S, Pc>
        where Self: Sized + CommandsList + CommandsListPossibleInsideRenderPass, Pl: PipelineLayoutRef,
              S: TrackedDescriptorSetsCollection, Pv: Source<V>
    {
        CmdDraw::new(self, pipeline, dynamic, vertices, sets, push_constants)
    }

    /// Appends this list of commands at the end of a command buffer in construction.
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
        // TODO: temporary body until all the impls implement this function
        unimplemented!()
    }

    /// Returns true if the command buffer can be built. This function should always return true,
    /// except when we're building a primary command buffer that is inside a render pass.
    // TODO: remove function
    #[deprecated]
    fn buildable_state(&self) -> bool { unimplemented!() }

    /// Returns the number of commands in the commands list.
    ///
    /// Note that multiple actual commands may count for just 1.
    // TODO: remove function
    #[deprecated]
    fn num_commands(&self) -> usize { unimplemented!() }

    /// Checks whether the command can be executed on the given queue family.
    // TODO: error type?
    // TODO: remove function
    #[deprecated]
    fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> { unimplemented!() }

    /// Extracts the object that contains the states of all the resources of the commands list.
    ///
    /// Panics if the states were already extracted.
    // TODO: remove function
    #[deprecated]
    fn extract_states(&mut self) -> StatesManager { unimplemented!() }

    /// Returns true if the given compute pipeline is currently binded in the commands list.
    // TODO: better API?
    // TODO: remove function
    #[deprecated]
    fn is_compute_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool { unimplemented!() }

    /// Returns true if the given graphics pipeline is currently binded in the commands list.
    // TODO: better API?
    // TODO: remove function
    #[deprecated]
    fn is_graphics_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool { unimplemented!() }
}

unsafe impl CommandsList for Box<CommandsList> {
    #[inline]
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
        (**self).append(builder)
    }
}

/// Output of the "append" method. The lifetime corresponds to the CommandsList.
pub trait CommandsListSink<'a> {
    fn device(&self) -> &Arc<Device>;

    /// Note that the lifetime means that we hold a reference to the content of
    /// the commands list in that closure.
    fn add_command(&mut self, Box<CommandsListSinkCaller<'a> + 'a>);

    fn add_buffer_transition(&mut self, buffer: &TrackedBuffer, offset: usize, size: usize,
                             write: bool);

    ///
    ///
    /// If necessary, you must transition the image to the `layout`.
    fn add_image_transition(&mut self, image: &TrackedImage, first_layer: u32, num_layers: u32,
                            first_mipmap: u32, num_mipmaps: u32, layout: Layout);

    fn add_image_transition_notification(&mut self, image: &TrackedImage, first_layer: u32,
                                         num_layers: u32, first_mipmap: u32, num_mipmaps: u32,
                                         layout: Layout);
}

pub trait CommandsListSinkCaller<'a> {
    fn call(self: Box<Self>, &mut RawCommandBufferPrototype<'a>);
}
impl<'a, T> CommandsListSinkCaller<'a> for T where T: FnOnce(&mut RawCommandBufferPrototype<'a>) -> () + 'a {
    fn call(self: Box<Self>, proto: &mut RawCommandBufferPrototype<'a>) {
        self(proto);
    }
}

#[deprecated]
pub unsafe trait CommandsListConcrete: CommandsList {
    type Pool: CommandPool;
    /// The type of the command buffer that will be generated.
    type Output: CommandsListOutput;

    /// Turns the commands list into a command buffer.
    ///
    /// This function accepts additional arguments that will customize the output:
    ///
    /// - `additional_elements` is a closure that must be called on the command buffer builder
    ///   after it has finished building and before `final_barrier` are added.
    /// - `barriers` is a list of pipeline barriers accompanied by a command number. The
    ///   pipeline barrier must happen after the given command number. Usually you want all the
    ///   the command numbers to be inferior to `num_commands`.
    /// - `final_barrier` is a pipeline barrier that must be added at the end of the
    ///   command buffer builder.
    ///
    /// This function doesn't check that `buildable_state` returns true.
    #[deprecated]
    unsafe fn raw_build<I, F>(self, in_s: &mut StatesManager, out: &mut StatesManager,
                              additional_elements: F, barriers: I,
                              final_barrier: PipelineBarrierBuilder) -> Self::Output
        where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
              I: Iterator<Item = (usize, PipelineBarrierBuilder)>;

    /// Turns the commands list into a command buffer that can be submitted.
    // This function isn't inline because `raw_build` implementations usually are inline.
    #[deprecated]
    fn build(mut self) -> CommandBuffer<Self::Output> where Self: Sized {
        assert!(self.buildable_state(), "Tried to build a command buffer still inside a \
                                         render pass");

        let mut states_in = self.extract_states();
        let mut states_out = StatesManager::new();

        let output = unsafe {
            self.raw_build(&mut states_in, &mut states_out, |_| {},
                           iter::empty(), PipelineBarrierBuilder::new())
        };

        CommandBuffer {
            states: states_out,
            commands: output,
        }
    }
}

/// Extension trait for both `CommandsList` and `CommandsListOutput` that indicates that we're
/// possibly outside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be outside
/// of a render pass. If it is implemented, then we maybe are but that's not sure.
pub unsafe trait CommandsListPossibleOutsideRenderPass {
    /// Returns `true` if we're outside a render pass.
    fn is_outside_render_pass(&self) -> bool;
}

/// Extension trait for both `CommandsList` and `CommandsListOutput` that indicates that we're
/// possibly inside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be inside
/// a render pass. If it is implemented, then we maybe are but that's not sure.
// TODO: make all return values optional, since we're possibly not in a render pass
pub unsafe trait CommandsListPossibleInsideRenderPass {
    type RenderPass: RenderPass;

    /// Returns the number of the subpass we're in. The value is 0-indexed, so immediately after
    /// calling `begin_render_pass` the value will be `0`.
    ///
    /// The value should always be strictly inferior to the number of subpasses in the render pass.
    fn current_subpass_num(&self) -> u32;

    /// If true, only secondary command buffers can be added inside the subpass. If false, only
    /// inline draw commands can be added.
    fn secondary_subpass(&self) -> bool;

    /// Returns the description of the render pass we're in.
    // TODO: return a trait object instead?
    fn render_pass(&self) -> &Self::RenderPass;

    //fn current_subpass(&self) -> Subpass<&Self::RenderPass>;
}

#[deprecated]
pub unsafe trait CommandsListOutput<S = StatesManager> {
    /// Returns the inner object.
    // TODO: crappy API
    #[deprecated]
    fn inner(&self) -> vk::CommandBuffer;

    /// Returns the device this object belongs to.
    #[deprecated]
    fn device(&self) -> &Arc<Device>;

    #[deprecated]
    unsafe fn on_submit(&self, states: &S, queue: &Arc<Queue>,
                        fence: &mut FnMut() -> Arc<Fence>) -> SubmitInfo;
}

#[deprecated]
pub struct CommandBuffer<C = Box<CommandsListOutput>> {
    states: StatesManager,
    commands: C,
}

unsafe impl<C> Submit for CommandBuffer<C> where C: CommandsListOutput {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.commands.device()
    }

    #[inline]
    unsafe fn append_submission<'a>(&'a self, mut base: SubmitBuilder<'a>, queue: &Arc<Queue>)
                                    -> Result<SubmitBuilder<'a>, Box<Error>>
    {
        let mut fence = None;
        let infos = self.commands.on_submit(&self.states, queue, &mut || {
            match &mut fence {
                f @ &mut None => {
                    let fe = Fence::new(self.device().clone()); *f = Some(fe.clone()); fe
                },
                &mut Some(ref f) => f.clone()
            }
        });

        for (sem_wait, sem_stage) in infos.semaphores_wait {
            base = base.add_wait_semaphore(sem_wait, sem_stage);
        }

        if !infos.pre_pipeline_barrier.is_empty() {
            unimplemented!()
        }

        base = base.add_command_buffer_raw(self.commands.inner());

        if !infos.post_pipeline_barrier.is_empty() {
            unimplemented!()
        }

        for sem_signal in infos.semaphores_signal {
            base = base.add_signal_semaphore(sem_signal);
        }

        if let Some(fence) = fence {
            base = base.add_fence_signal(fence);
        }

        Ok(base)
    }
}
<commit_msg>Some cleanup for old stuff<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error::Error;
use std::iter;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::DynamicState;
use command_buffer::pool::CommandPool;
use command_buffer::StatesManager;
use command_buffer::SubmitInfo;
use command_buffer::SubmitBuilder;
use command_buffer::Submit;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use descriptor::PipelineLayoutRef;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
use device::Device;
use device::Queue;
use framebuffer::traits::TrackedFramebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use image::Layout;
use image::TrackedImage;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::GraphicsPipeline;
use pipeline::vertex::Source;
use sync::Fence;
use vk;

pub use self::begin_render_pass::CmdBeginRenderPass;
pub use self::bind_index_buffer::CmdBindIndexBuffer;
pub use self::bind_descriptor_sets::{CmdBindDescriptorSets, CmdBindDescriptorSetsError};
pub use self::bind_pipeline::CmdBindPipeline;
pub use self::bind_vertex_buffers::CmdBindVertexBuffers;
pub use self::blit_image_unsynced::{BlitRegion, BlitRegionAspect};
pub use self::blit_image_unsynced::{CmdBlitImageUnsynced, CmdBlitImageUnsyncedError};
pub use self::copy_buffer::{CmdCopyBuffer, CmdCopyBufferError};
pub use self::dispatch::CmdDispatch;
pub use self::draw::CmdDraw;
pub use self::empty::{empty, EmptyCommandsList};
pub use self::end_render_pass::CmdEndRenderPass;
pub use self::fill_buffer::{CmdFillBuffer, CmdFillBufferError};
pub use self::next_subpass::CmdNextSubpass;
pub use self::push_constants::{CmdPushConstants, CmdPushConstantsError};
pub use self::set_state::{CmdSetState};
pub use self::update_buffer::{CmdUpdateBuffer, CmdUpdateBufferError};

mod begin_render_pass;
mod bind_descriptor_sets;
mod bind_index_buffer;
mod bind_pipeline;
mod bind_vertex_buffers;
mod blit_image_unsynced;
mod copy_buffer;
mod dispatch;
mod draw;
mod empty;
mod end_render_pass;
//pub mod execute;      // TODO: reenable when the concept of a command buffer is well defined
mod fill_buffer;
mod next_subpass;
mod push_constants;
mod set_state;
mod update_buffer;

/// A list of commands that can be turned into a command buffer.
///
/// This is just a naked list of commands. It stores buffers, images, etc. but the list of commands
/// itself is not a Vulkan object.
pub unsafe trait CommandsList {
    /// Adds a command that writes the content of a buffer.
    ///
    /// After this command is executed, the content of `buffer` will become `data`.
    #[inline]
    fn update_buffer<'a, B, D: ?Sized>(self, buffer: B, data: &'a D)
                                       -> Result<CmdUpdateBuffer<'a, Self, B, D>, CmdUpdateBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer, D: Copy + 'static
    {
        CmdUpdateBuffer::new(self, buffer, data)
    }

    /// Adds a command that copies the content of a buffer to another.
    #[inline]
    fn copy_buffer<S, D>(self, source: S, destination: D)
                         -> Result<CmdCopyBuffer<Self, S, D>, CmdCopyBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass,
              S: TrackedBuffer, D: TrackedBuffer
    {
        CmdCopyBuffer::new(self, source, destination)
    }

    /// Adds a command that writes the content of a buffer.
    #[inline]
    fn fill_buffer<B>(self, buffer: B, data: u32)
                      -> Result<CmdFillBuffer<Self, B>, CmdFillBufferError>
        where Self: Sized + CommandsListPossibleOutsideRenderPass, B: TrackedBuffer
    {
        CmdFillBuffer::new(self, buffer, data)
    }

    // TODO: reenable
    /*/// Adds a command that executes a secondary command buffer.
    ///
    /// When you create a command buffer, you have the possibility to create either a primary
    /// command buffer or a secondary command buffer. Secondary command buffers can't be executed
    /// directly, but can be executed from a primary command buffer.
    ///
    /// A secondary command buffer can't execute another secondary command buffer. The only way
    /// you can use `execute` is to make a primary command buffer call a secondary command buffer.
    #[inline]
    fn execute<Cb>(self, command_buffer: Cb) -> execute::ExecuteCommand<Cb, Self>
        where Self: Sized, Cb: CommandsListOutput       /* FIXME: */
    {
        execute::ExecuteCommand::new(self, command_buffer)
    }*/

    /// Adds a command that executes a compute shader.
    ///
    /// The `dimensions` are the number of working groups to start. The GPU will execute the
    /// compute shader `dimensions[0] * dimensions[1] * dimensions[2]` times.
    ///
    /// The `pipeline` is the compute pipeline that will be executed, and the sets and push
    /// constants will be accessible to all the invocations.
    #[inline]
    fn dispatch<Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
                           dimensions: [u32; 3], push_constants: Pc)
                           -> CmdDispatch<Self, Pl, S, Pc>
        where Self: Sized + CommandsList, Pl: PipelineLayoutRef,
              S: TrackedDescriptorSetsCollection
    {
        CmdDispatch::new(self, pipeline, sets, dimensions, push_constants)
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass on the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C>(self, framebuffer: F, secondary: bool, clear_values: C)
                               -> CmdBeginRenderPass<Self, F::RenderPass, F>
        where Self: Sized, F: TrackedFramebuffer,
              F::RenderPass: RenderPass + RenderPassClearValues<C>
    {
        CmdBeginRenderPass::new(self, framebuffer, secondary, clear_values)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass(self, secondary: bool) -> CmdNextSubpass<Self>
        where Self: Sized
    {
        CmdNextSubpass::new(self, secondary)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass(self) -> CmdEndRenderPass<Self>
        where Self: Sized
    {
        CmdEndRenderPass::new(self)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<Pv, Pl, Prp, S, Pc, V>(self, pipeline: Arc<GraphicsPipeline<Pv, Pl, Prp>>,
                                   dynamic: DynamicState, vertices: V, sets: S,
                                   push_constants: Pc)
                                   -> CmdDraw<Self, V, Pv, Pl, Prp, S, Pc>
        where Self: Sized + CommandsList + CommandsListPossibleInsideRenderPass, Pl: PipelineLayoutRef,
              S: TrackedDescriptorSetsCollection, Pv: Source<V>
    {
        CmdDraw::new(self, pipeline, dynamic, vertices, sets, push_constants)
    }

    /// Appends this list of commands at the end of a command buffer in construction.
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>);
}

unsafe impl CommandsList for Box<CommandsList> {
    #[inline]
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
        (**self).append(builder)
    }
}

/// Output of the "append" method. The lifetime corresponds to the CommandsList.
pub trait CommandsListSink<'a> {
    fn device(&self) -> &Arc<Device>;

    /// Note that the lifetime means that we hold a reference to the content of
    /// the commands list in that closure.
    fn add_command(&mut self, Box<CommandsListSinkCaller<'a> + 'a>);

    fn add_buffer_transition(&mut self, buffer: &TrackedBuffer, offset: usize, size: usize,
                             write: bool);

    ///
    ///
    /// If necessary, you must transition the image to the `layout`.
    fn add_image_transition(&mut self, image: &TrackedImage, first_layer: u32, num_layers: u32,
                            first_mipmap: u32, num_mipmaps: u32, layout: Layout);

    fn add_image_transition_notification(&mut self, image: &TrackedImage, first_layer: u32,
                                         num_layers: u32, first_mipmap: u32, num_mipmaps: u32,
                                         layout: Layout);
}

pub trait CommandsListSinkCaller<'a> {
    fn call(self: Box<Self>, &mut RawCommandBufferPrototype<'a>);
}
impl<'a, T> CommandsListSinkCaller<'a> for T where T: FnOnce(&mut RawCommandBufferPrototype<'a>) -> () + 'a {
    fn call(self: Box<Self>, proto: &mut RawCommandBufferPrototype<'a>) {
        self(proto);
    }
}

/// Extension trait for both `CommandsList` and `CommandsListOutput` that indicates that we're
/// possibly outside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be outside
/// of a render pass. If it is implemented, then we maybe are but that's not sure.
pub unsafe trait CommandsListPossibleOutsideRenderPass {
    /// Returns `true` if we're outside a render pass.
    fn is_outside_render_pass(&self) -> bool;
}

/// Extension trait for both `CommandsList` and `CommandsListOutput` that indicates that we're
/// possibly inside a render pass.
///
/// In other words, if this trait is *not* implemented then we're guaranteed *not* to be inside
/// a render pass. If it is implemented, then we maybe are but that's not sure.
// TODO: make all return values optional, since we're possibly not in a render pass
pub unsafe trait CommandsListPossibleInsideRenderPass {
    type RenderPass: RenderPass;

    /// Returns the number of the subpass we're in. The value is 0-indexed, so immediately after
    /// calling `begin_render_pass` the value will be `0`.
    ///
    /// The value should always be strictly inferior to the number of subpasses in the render pass.
    fn current_subpass_num(&self) -> u32;

    /// If true, only secondary command buffers can be added inside the subpass. If false, only
    /// inline draw commands can be added.
    fn secondary_subpass(&self) -> bool;

    /// Returns the description of the render pass we're in.
    // TODO: return a trait object instead?
    fn render_pass(&self) -> &Self::RenderPass;

    //fn current_subpass(&self) -> Subpass<&Self::RenderPass>;
}

#[deprecated]
pub unsafe trait CommandsListOutput<S = StatesManager> {
    /// Returns the inner object.
    // TODO: crappy API
    #[deprecated]
    fn inner(&self) -> vk::CommandBuffer;

    /// Returns the device this object belongs to.
    #[deprecated]
    fn device(&self) -> &Arc<Device>;

    #[deprecated]
    unsafe fn on_submit(&self, states: &S, queue: &Arc<Queue>,
                        fence: &mut FnMut() -> Arc<Fence>) -> SubmitInfo;
}

#[deprecated]
pub struct CommandBuffer<C = Box<CommandsListOutput>> {
    states: StatesManager,
    commands: C,
}

unsafe impl<C> Submit for CommandBuffer<C> where C: CommandsListOutput {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.commands.device()
    }

    #[inline]
    unsafe fn append_submission<'a>(&'a self, mut base: SubmitBuilder<'a>, queue: &Arc<Queue>)
                                    -> Result<SubmitBuilder<'a>, Box<Error>>
    {
        let mut fence = None;
        let infos = self.commands.on_submit(&self.states, queue, &mut || {
            match &mut fence {
                f @ &mut None => {
                    let fe = Fence::new(self.device().clone()); *f = Some(fe.clone()); fe
                },
                &mut Some(ref f) => f.clone()
            }
        });

        for (sem_wait, sem_stage) in infos.semaphores_wait {
            base = base.add_wait_semaphore(sem_wait, sem_stage);
        }

        if !infos.pre_pipeline_barrier.is_empty() {
            unimplemented!()
        }

        base = base.add_command_buffer_raw(self.commands.inner());

        if !infos.post_pipeline_barrier.is_empty() {
            unimplemented!()
        }

        for sem_signal in infos.semaphores_signal {
            base = base.add_signal_semaphore(sem_signal);
        }

        if let Some(fence) = fence {
            base = base.add_fence_signal(fence);
        }

        Ok(base)
    }
}
<|endoftext|>


<commit_before>//! A simple parser for a tiny subset of HTML.
//!
//! Can parse basic opening and closing tags, and text nodes.
//!
//! Not yet supported:
//!
//! * Comments
//! * Doctypes and processing instructions
//! * Self-closing tags
//! * Non-well-formed markup
//! * Character entities

use dom;
use std::collections::hashmap::HashMap;

/// Parse an HTML document and return the root element.
pub fn parse(source: String) -> dom::Node {
    let mut nodes = Parser { pos: 0u, input: source }.parse_nodes();

    // If the document contains a root element, just return it. Otherwise, create one.
    if nodes.len() == 1 {
        nodes.swap_remove(0).unwrap()
    } else {
        dom::elem("html".to_string(), HashMap::new(), nodes)
    }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a sequence of sibling nodes.
    fn parse_nodes(&mut self) -> Vec<dom::Node> {
        let mut nodes = vec!();
        loop {
            self.consume_whitespace();
            if self.eof() || self.starts_with("</") {
                break;
            }
            nodes.push(self.parse_node());
        }
        nodes
    }

    /// Parse a single node.
    fn parse_node(&mut self) -> dom::Node {
        match self.next_char() {
            '<' => self.parse_element(),
            _   => self.parse_text()
        }
    }

    /// Parse a single element, including its open tag, contents, and closing tag.
    fn parse_element(&mut self) -> dom::Node {
        // Opening tag.
        assert!(self.consume_char() == '<');
        let tag_name = self.parse_tag_name();
        let attrs = self.parse_attributes();
        assert!(self.consume_char() == '>');

        // Contents.
        let children = self.parse_nodes();

        // Closing tag.
        assert!(self.consume_char() == '<');
        assert!(self.consume_char() == '/');
        assert!(self.parse_tag_name() == tag_name);
        assert!(self.consume_char() == '>');

        dom::elem(tag_name, attrs, children)
    }

    /// Parse a tag or attribute name.
    fn parse_tag_name(&mut self) -> String {
        self.consume_while(|c| match c {
            'a'..'z' | 'A'..'Z' | '0'..'9' => true,
            _ => false
        })
    }

    /// Parse a list of name="value" pairs, separated by whitespace.
    fn parse_attributes(&mut self) -> dom::AttrMap {
        let mut attributes = HashMap::new();
        loop {
            self.consume_whitespace();
            match self.next_char() {
                '>' => break,
                _ => {
                    let (name, value) = self.parse_attr();
                    attributes.insert(name, value);
                }
            }
        }
        attributes
    }

    /// Parse a single name="value" pair.
    fn parse_attr(&mut self) -> (String, String) {
        let name = self.parse_tag_name();
        assert!(self.consume_char() == '=');
        let value = self.parse_attr_value();
        (name, value)
    }

    /// Parse a quoted value.
    fn parse_attr_value(&mut self) -> String {
        let open_quote = self.consume_char();
        assert!(open_quote == '"' || open_quote == '\'');
        let value = self.consume_while(|c| c != open_quote);
        assert!(self.consume_char() == open_quote);
        value
    }

    /// Parse a text node.
    fn parse_text(&mut self) -> dom::Node {
        dom::text(self.consume_while(|c| c != '<'))
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Does the current input start with the given string?
    fn starts_with(&self, s: &str) -> bool {
        self.input.as_slice().slice_from(self.pos).starts_with(s)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}
<commit_msg>Tiny code cleanup in parse_attributes<commit_after>//! A simple parser for a tiny subset of HTML.
//!
//! Can parse basic opening and closing tags, and text nodes.
//!
//! Not yet supported:
//!
//! * Comments
//! * Doctypes and processing instructions
//! * Self-closing tags
//! * Non-well-formed markup
//! * Character entities

use dom;
use std::collections::hashmap::HashMap;

/// Parse an HTML document and return the root element.
pub fn parse(source: String) -> dom::Node {
    let mut nodes = Parser { pos: 0u, input: source }.parse_nodes();

    // If the document contains a root element, just return it. Otherwise, create one.
    if nodes.len() == 1 {
        nodes.swap_remove(0).unwrap()
    } else {
        dom::elem("html".to_string(), HashMap::new(), nodes)
    }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a sequence of sibling nodes.
    fn parse_nodes(&mut self) -> Vec<dom::Node> {
        let mut nodes = vec!();
        loop {
            self.consume_whitespace();
            if self.eof() || self.starts_with("</") {
                break;
            }
            nodes.push(self.parse_node());
        }
        nodes
    }

    /// Parse a single node.
    fn parse_node(&mut self) -> dom::Node {
        match self.next_char() {
            '<' => self.parse_element(),
            _   => self.parse_text()
        }
    }

    /// Parse a single element, including its open tag, contents, and closing tag.
    fn parse_element(&mut self) -> dom::Node {
        // Opening tag.
        assert!(self.consume_char() == '<');
        let tag_name = self.parse_tag_name();
        let attrs = self.parse_attributes();
        assert!(self.consume_char() == '>');

        // Contents.
        let children = self.parse_nodes();

        // Closing tag.
        assert!(self.consume_char() == '<');
        assert!(self.consume_char() == '/');
        assert!(self.parse_tag_name() == tag_name);
        assert!(self.consume_char() == '>');

        dom::elem(tag_name, attrs, children)
    }

    /// Parse a tag or attribute name.
    fn parse_tag_name(&mut self) -> String {
        self.consume_while(|c| match c {
            'a'..'z' | 'A'..'Z' | '0'..'9' => true,
            _ => false
        })
    }

    /// Parse a list of name="value" pairs, separated by whitespace.
    fn parse_attributes(&mut self) -> dom::AttrMap {
        let mut attributes = HashMap::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '>' {
                break;
            }
            let (name, value) = self.parse_attr();
            attributes.insert(name, value);
        }
        attributes
    }

    /// Parse a single name="value" pair.
    fn parse_attr(&mut self) -> (String, String) {
        let name = self.parse_tag_name();
        assert!(self.consume_char() == '=');
        let value = self.parse_attr_value();
        (name, value)
    }

    /// Parse a quoted value.
    fn parse_attr_value(&mut self) -> String {
        let open_quote = self.consume_char();
        assert!(open_quote == '"' || open_quote == '\'');
        let value = self.consume_while(|c| c != open_quote);
        assert!(self.consume_char() == open_quote);
        value
    }

    /// Parse a text node.
    fn parse_text(&mut self) -> dom::Node {
        dom::text(self.consume_while(|c| c != '<'))
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push_char(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        range.ch
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Does the current input start with the given string?
    fn starts_with(&self, s: &str) -> bool {
        self.input.as_slice().slice_from(self.pos).starts_with(s)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::marker::PhantomData;
use num::Float;
use operate::Operate;
use stack::Stack;
use ::pop_two_operands;

// Add  (+)      pop 2, push 1
// Sub  (-)      pop 2, push 1
// Mul  (*)      pop 2, push 1
// Div  (/)      pop 2, push 1
// Rem  (%)      pop 2, push 1
// Neg  (neg)    pop 1, push 1
// Sqrt (sqrt)   pop 1, push 1
// Pow  (pow)    pop 1, push 1
// Log2 (log2)   pop 1, push 1
// Exp  (exp)    pop 1, push 1
// Swap (swap)   pop 2, push 2
// Zero (zero)   pop 0, push 1
// One  (zero)   pop 0, push 1
// Round (round) pop 1, push 1

#[derive(Debug, Copy, Clone)]
pub enum FloatOperator<T: Float> {
    Add(PhantomData<T>),
    Sub(PhantomData<T>),
    Mul(PhantomData<T>),
    Div(PhantomData<T>),
    Rem(PhantomData<T>),
    Neg(PhantomData<T>),
    Sqrt(PhantomData<T>),
    Pow(PhantomData<T>),
    Log2(PhantomData<T>),
    Exp(PhantomData<T>),
    Swap(PhantomData<T>),
    Zero(PhantomData<T>),
    One(PhantomData<T>),
    Round(PhantomData<T>),
}

#[derive(Debug, PartialEq)]
pub enum FloatOperateErr {
    // TODO add variants
}

impl<T: Float> Operate<T> for FloatOperator<T> {
    type Err = FloatOperateErr;

    fn operands_needed(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
            Add(_) | Sub(_) | Mul(_) | Div(_) | Pow(_) | Rem(_) | Swap(_) => 2,
            Neg(_) | Sqrt(_) | Log2(_) | Round(_) | Exp(_) => 1,
            Zero(_) | One(_) => 0,
        }
    }

    fn operands_generated(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
            Add(_) | Sub(_) | Mul(_) | Div(_) | Rem(_) | Neg(_) | Sqrt(_) | Pow(_) | Log2(_) |
            Exp(_) | Zero(_) | One(_) | Round(_) => 1,
            Swap(_) => 2,
        }
    }

    fn operate(self, stack: &mut Stack<T>) -> Result<(), Self::Err> {
        use self::FloatOperator::*;
        match self {
            Add(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a + b))
            }
            Sub(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b - a))
            }
            Mul(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a * b))
            }
            Div(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b / a))
            }
            Rem(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b % a))
            }
            Neg(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(-a))
            }
            Sqrt(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.sqrt()))
            }
            Pow(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b.powf(a)))
            }
            Log2(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.log2()))
            }
            Exp(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.exp()))
            }
            Swap(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                stack.push(a);
                stack.push(b);
                Ok(())
            }
            Zero(_) => Ok(stack.push(T::zero())),
            One(_) => Ok(stack.push(T::one())),
            Round(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.round()))
            }
        }
    }
}

#[derive(Debug)]
pub enum FloatErr<'a> {
    InvalidExpr(&'a str),
}

impl<'a, T: Float> TryFrom<&'a str> for FloatOperator<T> {
    type Err = FloatErr<'a>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        use self::FloatOperator::*;
        match expr {
            "+" => Ok(Add(PhantomData::default())),
            "-" => Ok(Sub(PhantomData::default())),
            "*" => Ok(Mul(PhantomData::default())),
            "/" => Ok(Div(PhantomData::default())),
            "%" => Ok(Rem(PhantomData::default())),
            "neg" => Ok(Neg(PhantomData::default())),
            "sqrt" => Ok(Sqrt(PhantomData::default())),
            "pow" => Ok(Pow(PhantomData::default())),
            "log2" => Ok(Log2(PhantomData::default())),
            "exp" => Ok(Exp(PhantomData::default())),
            "swap" => Ok(Swap(PhantomData::default())),
            "zero" => Ok(Zero(PhantomData::default())),
            "one" => Ok(One(PhantomData::default())),
            "round" => Ok(Round(PhantomData::default())),
            _ => Err(FloatErr::InvalidExpr(expr)),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;
    use expression::{Expression, ExprResult};
    use operate::{FloatOperator, FloatErr};

    #[test]
    fn bad_operator() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "3 4 + &".try_into();
        match res {
            Err(ExprResult::InvalidToken(_, FloatErr::InvalidExpr("&"))) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn too_many_operands() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "3 3 4 +".try_into();
        match res {
            Err(ExprResult::TooManyOperands) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn not_enough_operand() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "4 +".try_into();
        match res {
            Err(ExprResult::NotEnoughOperand) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn simple_addition() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 +".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(7.0));
    }

    #[test]
    fn simple_substraction() {
        let expr: Expression<f32, FloatOperator<_>> = "4 3 -".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_multiplication() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 *".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(12.0));
    }

    #[test]
    fn simple_division() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_remaining() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 %".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_negation() {
        let expr: Expression<f32, FloatOperator<_>> = "9 neg".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(-9.0));
    }

    #[test]
    fn simple_square_root() {
        let expr: Expression<f32, FloatOperator<_>> = "9 sqrt".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_power() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 pow".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(81.0));
    }

    #[test]
    fn simple_logarithm_2() {
        let expr: Expression<f32, FloatOperator<_>> = "4 log2".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_exponential() {
        let expr: Expression<f32, FloatOperator<_>> = "0 exp".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_swap() {
        let expr: Expression<f32, FloatOperator<_>> = "2 4 swap /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_zero() {
        let expr: Expression<f32, FloatOperator<_>> = "zero".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_one() {
        let expr: Expression<f32, FloatOperator<_>> = "one".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_round() {
        let expr: Expression<f32, FloatOperator<_>> = "3.3 round".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }
}
<commit_msg>operate: Add test for strange cases<commit_after>use std::convert::TryFrom;
use std::marker::PhantomData;
use num::Float;
use operate::Operate;
use stack::Stack;
use ::pop_two_operands;

#[derive(Debug, Copy, Clone)]
pub enum FloatOperator<T: Float> {
    /// `"+"` will pop `2` operands and push `1`.
    Add(PhantomData<T>),

    /// `"-"` will pop `2` operands and push `1`.
    Sub(PhantomData<T>),

    /// `"*"` will pop `2` operands and push `1`.
    Mul(PhantomData<T>),

    /// `"/"` will pop `2` operands and push `1`.
    Div(PhantomData<T>),

    /// `"%"` will pop `2` operands and push `1`.
    Rem(PhantomData<T>),

    /// `"neg"` will pop `1` operand and push `1`.
    Neg(PhantomData<T>),

    /// `"sqrt"` will pop `1` operand and push `1`.
    Sqrt(PhantomData<T>),

    /// `"pow"` will pop `1` operand and push `1`.
    Pow(PhantomData<T>),

    /// `"log2"` will pop `1` operand and push `1`.
    Log2(PhantomData<T>),

    /// `"exp"` will pop `1` operand and push `1`.
    Exp(PhantomData<T>),

    /// `"swap"` will pop `2` operands and push `2`.
    Swap(PhantomData<T>),

    /// `"zero"` will pop `0` operand and push `1`.
    Zero(PhantomData<T>),

    /// `"zero"` will pop `0` operand and push `1`.
    One(PhantomData<T>),

    /// `"round"` will pop `1` operand and push `1`.
    Round(PhantomData<T>),
}

#[derive(Debug, PartialEq)]
pub enum FloatOperateErr {
    // TODO add variants
}

impl<T: Float> Operate<T> for FloatOperator<T> {
    type Err = FloatOperateErr;

    fn operands_needed(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
            Add(_) | Sub(_) | Mul(_) | Div(_) | Pow(_) | Rem(_) | Swap(_) => 2,
            Neg(_) | Sqrt(_) | Log2(_) | Round(_) | Exp(_) => 1,
            Zero(_) | One(_) => 0,
        }
    }

    fn operands_generated(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
            Add(_) | Sub(_) | Mul(_) | Div(_) | Rem(_) | Neg(_) | Sqrt(_) | Pow(_) | Log2(_) |
            Exp(_) | Zero(_) | One(_) | Round(_) => 1,
            Swap(_) => 2,
        }
    }

    fn operate(self, stack: &mut Stack<T>) -> Result<(), Self::Err> {
        use self::FloatOperator::*;
        match self {
            Add(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a + b))
            }
            Sub(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b - a))
            }
            Mul(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a * b))
            }
            Div(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b / a))
            }
            Rem(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b % a))
            }
            Neg(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(-a))
            }
            Sqrt(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.sqrt()))
            }
            Pow(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b.powf(a)))
            }
            Log2(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.log2()))
            }
            Exp(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.exp()))
            }
            Swap(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                stack.push(a);
                stack.push(b);
                Ok(())
            }
            Zero(_) => Ok(stack.push(T::zero())),
            One(_) => Ok(stack.push(T::one())),
            Round(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.round()))
            }
        }
    }
}

#[derive(Debug)]
pub enum FloatErr<'a> {
    InvalidExpr(&'a str),
}

impl<'a, T: Float> TryFrom<&'a str> for FloatOperator<T> {
    type Err = FloatErr<'a>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        use self::FloatOperator::*;
        match expr {
            "+" => Ok(Add(PhantomData::default())),
            "-" => Ok(Sub(PhantomData::default())),
            "*" => Ok(Mul(PhantomData::default())),
            "/" => Ok(Div(PhantomData::default())),
            "%" => Ok(Rem(PhantomData::default())),
            "neg" => Ok(Neg(PhantomData::default())),
            "sqrt" => Ok(Sqrt(PhantomData::default())),
            "pow" => Ok(Pow(PhantomData::default())),
            "log2" => Ok(Log2(PhantomData::default())),
            "exp" => Ok(Exp(PhantomData::default())),
            "swap" => Ok(Swap(PhantomData::default())),
            "zero" => Ok(Zero(PhantomData::default())),
            "one" => Ok(One(PhantomData::default())),
            "round" => Ok(Round(PhantomData::default())),
            _ => Err(FloatErr::InvalidExpr(expr)),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;
    use expression::{Expression, ExprResult};
    use operate::{FloatOperator, FloatErr};

    #[test]
    fn bad_operator() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "3 4 + &".try_into();
        match res {
            Err(ExprResult::InvalidToken(_, FloatErr::InvalidExpr("&"))) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn too_many_operands() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "3 3 4 +".try_into();
        match res {
            Err(ExprResult::TooManyOperands) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn not_enough_operand() {
        let res: Result<Expression<f32, FloatOperator<_>>, _> = "4 +".try_into();
        match res {
            Err(ExprResult::NotEnoughOperand) => (),
            _ => panic!(res),
        }
    }

    #[test]
    fn simple_addition() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 +".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(7.0));
    }

    #[test]
    fn simple_substraction() {
        let expr: Expression<f32, FloatOperator<_>> = "4 3 -".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_multiplication() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 *".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(12.0));
    }

    #[test]
    fn simple_division() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_division_by_zero() {
        use std::f32;
        let expr: Expression<f32, FloatOperator<_>> = "9 0 /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(f32::INFINITY));
    }

    #[test]
    fn simple_nan() {
        let expr: Expression<f32, FloatOperator<_>> = "0 0 /".try_into().unwrap();
        assert!(expr.operate().unwrap().is_nan());
    }

    #[test]
    fn simple_remaining() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 %".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_negation() {
        let expr: Expression<f32, FloatOperator<_>> = "9 neg".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(-9.0));
    }

    #[test]
    fn simple_square_root() {
        let expr: Expression<f32, FloatOperator<_>> = "9 sqrt".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_power() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 pow".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(81.0));
    }

    #[test]
    fn simple_logarithm_2() {
        let expr: Expression<f32, FloatOperator<_>> = "4 log2".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_exponential() {
        let expr: Expression<f32, FloatOperator<_>> = "0 exp".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_swap() {
        let expr: Expression<f32, FloatOperator<_>> = "2 4 swap /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_zero() {
        let expr: Expression<f32, FloatOperator<_>> = "zero".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_one() {
        let expr: Expression<f32, FloatOperator<_>> = "one".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_round() {
        let expr: Expression<f32, FloatOperator<_>> = "3.3 round".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use ra_syntax::{
    SourceFile, TextRange, TextUnit, AstNode, SyntaxNode,
    SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK},
    algo::find_covering_node,
    ast,
};
use ra_fmt::{
    compute_ws, extract_trivial_expression
};
use crate::{
    LocalEdit, TextEditBuilder,
};

pub fn join_lines(file: &SourceFile, range: TextRange) -> LocalEdit {
    let range = if range.is_empty() {
        let syntax = file.syntax();
        let text = syntax.text().slice(range.start()..);
        let pos = match text.find('\n') {
            None => {
                return LocalEdit {
                    label: "join lines".to_string(),
                    edit: TextEditBuilder::default().finish(),
                    cursor_position: None,
                };
            }
            Some(pos) => pos,
        };
        TextRange::offset_len(range.start() + pos, TextUnit::of_char('\n'))
    } else {
        range
    };

    let node = find_covering_node(file.syntax(), range);
    let mut edit = TextEditBuilder::default();
    for node in node.descendants() {
        let text = match node.leaf_text() {
            Some(text) => text,
            None => continue,
        };
        let range = match range.intersection(&node.range()) {
            Some(range) => range,
            None => continue,
        } - node.range().start();
        for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
            let pos: TextUnit = (pos as u32).into();
            let off = node.range().start() + range.start() + pos;
            if !edit.invalidates_offset(off) {
                remove_newline(&mut edit, node, text.as_str(), off);
            }
        }
    }

    LocalEdit { label: "join lines".to_string(), edit: edit.finish(), cursor_position: None }
}

fn remove_newline(
    edit: &mut TextEditBuilder,
    node: &SyntaxNode,
    node_text: &str,
    offset: TextUnit,
) {
    if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 {
        // The node is either the first or the last in the file
        let suff = &node_text[TextRange::from_to(
            offset - node.range().start() + TextUnit::of_char('\n'),
            TextUnit::of_str(node_text),
        )];
        let spaces = suff.bytes().take_while(|&b| b == b' ').count();

        edit.replace(TextRange::offset_len(offset, ((spaces + 1) as u32).into()), " ".to_string());
        return;
    }

    // Special case that turns something like:
    //
    // ```
    // my_function({<|>
    //    <some-expr>
    // })
    // ```
    //
    // into `my_function(<some-expr>)`
    if join_single_expr_block(edit, node).is_some() {
        return;
    }
    // ditto for
    //
    // ```
    // use foo::{<|>
    //    bar
    // };
    // ```
    if join_single_use_tree(edit, node).is_some() {
        return;
    }

    // The node is between two other nodes
    let prev = node.prev_sibling().unwrap();
    let next = node.next_sibling().unwrap();
    if is_trailing_comma(prev.kind(), next.kind()) {
        // Removes: trailing comma, newline (incl. surrounding whitespace)
        edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
    } else if prev.kind() == COMMA && next.kind() == R_CURLY {
        // Removes: comma, newline (incl. surrounding whitespace)
        let space = if let Some(left) = prev.prev_sibling() { compute_ws(left, next) } else { " " };
        edit.replace(
            TextRange::from_to(prev.range().start(), node.range().end()),
            space.to_string(),
        );
    } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) {
        // Removes: newline (incl. surrounding whitespace), start of the next comment
        edit.delete(TextRange::from_to(
            node.range().start(),
            next.syntax().range().start() + TextUnit::of_str(next.prefix()),
        ));
    } else {
        // Remove newline but add a computed amount of whitespace characters
        edit.replace(node.range(), compute_ws(prev, next).to_string());
    }
}

fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
    let block = ast::Block::cast(node.parent()?)?;
    let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
    let expr = extract_trivial_expression(block)?;
    edit.replace(block_expr.syntax().range(), expr.syntax().text().to_string());
    Some(())
}

fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
    let use_tree_list = ast::UseTreeList::cast(node.parent()?)?;
    let (tree,) = use_tree_list.use_trees().collect_tuple()?;
    edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string());
    Some(())
}

fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
    match (left, right) {
        (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,
        _ => false,
    }
}

#[cfg(test)]
mod tests {
    use crate::test_utils::{assert_eq_text, check_action, extract_range};

    use super::*;

    fn check_join_lines(before: &str, after: &str) {
        check_action(before, after, |file, offset| {
            let range = TextRange::offset_len(offset, 0.into());
            let res = join_lines(file, range);
            Some(res)
        })
    }

    #[test]
    fn test_join_lines_comma() {
        check_join_lines(
            r"
fn foo() {
    <|>foo(1,
    )
}
",
            r"
fn foo() {
    <|>foo(1)
}
",
        );
    }

    #[test]
    fn test_join_lines_lambda_block() {
        check_join_lines(
            r"
pub fn reparse(&self, edit: &AtomTextEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| {
        self.full_reparse(edit)
    })
}
",
            r"
pub fn reparse(&self, edit: &AtomTextEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
}
",
        );
    }

    #[test]
    fn test_join_lines_block() {
        check_join_lines(
            r"
fn foo() {
    foo(<|>{
        92
    })
}",
            r"
fn foo() {
    foo(<|>92)
}",
        );
    }

    #[test]
    fn test_join_lines_use_items_left() {
        // No space after the '{'
        check_join_lines(
            r"
<|>use ra_syntax::{
    TextUnit, TextRange,
};",
            r"
<|>use ra_syntax::{TextUnit, TextRange,
};",
        );
    }

    #[test]
    fn test_join_lines_use_items_right() {
        // No space after the '}'
        check_join_lines(
            r"
use ra_syntax::{
<|>    TextUnit, TextRange
};",
            r"
use ra_syntax::{
<|>    TextUnit, TextRange};",
        );
    }

    #[test]
    fn test_join_lines_use_items_right_comma() {
        // No space after the '}'
        check_join_lines(
            r"
use ra_syntax::{
<|>    TextUnit, TextRange,
};",
            r"
use ra_syntax::{
<|>    TextUnit, TextRange};",
        );
    }

    #[test]
    fn test_join_lines_use_tree() {
        check_join_lines(
            r"
use ra_syntax::{
    algo::<|>{
        find_leaf_at_offset,
    },
    ast,
};",
            r"
use ra_syntax::{
    algo::<|>find_leaf_at_offset,
    ast,
};",
        );
    }

    #[test]
    fn test_join_lines_normal_comments() {
        check_join_lines(
            r"
fn foo() {
    // Hello<|>
    // world!
}
",
            r"
fn foo() {
    // Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_doc_comments() {
        check_join_lines(
            r"
fn foo() {
    /// Hello<|>
    /// world!
}
",
            r"
fn foo() {
    /// Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_mod_comments() {
        check_join_lines(
            r"
fn foo() {
    //! Hello<|>
    //! world!
}
",
            r"
fn foo() {
    //! Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_multiline_comments_1() {
        check_join_lines(
            r"
fn foo() {
    // Hello<|>
    /* world! */
}
",
            r"
fn foo() {
    // Hello<|> world! */
}
",
        );
    }

    #[test]
    fn test_join_lines_multiline_comments_2() {
        check_join_lines(
            r"
fn foo() {
    // The<|>
    /* quick
    brown
    fox! */
}
",
            r"
fn foo() {
    // The<|> quick
    brown
    fox! */
}
",
        );
    }

    fn check_join_lines_sel(before: &str, after: &str) {
        let (sel, before) = extract_range(before);
        let file = SourceFile::parse(&before);
        let result = join_lines(&file, sel);
        let actual = result.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_join_lines_selection_fn_args() {
        check_join_lines_sel(
            r"
fn foo() {
    <|>foo(1,
        2,
        3,
    <|>)
}
    ",
            r"
fn foo() {
    foo(1, 2, 3)
}
    ",
        );
    }

    #[test]
    fn test_join_lines_selection_struct() {
        check_join_lines_sel(
            r"
struct Foo <|>{
    f: u32,
}<|>
    ",
            r"
struct Foo { f: u32 }
    ",
        );
    }

    #[test]
    fn test_join_lines_selection_dot_chain() {
        check_join_lines_sel(
            r"
fn foo() {
    join(<|>type_params.type_params()
            .filter_map(|it| it.name())
            .map(|it| it.text())<|>)
}",
            r"
fn foo() {
    join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()))
}",
        );
    }

    #[test]
    fn test_join_lines_selection_lambda_block_body() {
        check_join_lines_sel(
            r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| <|>{
            world.analysis().matching_brace(&file, offset).unwrap_or(offset)
        }<|>)
        .collect();
}",
            r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset))
        .collect();
}",
        );
    }
}
<commit_msg>add failing test<commit_after>use itertools::Itertools;
use ra_syntax::{
    SourceFile, TextRange, TextUnit, AstNode, SyntaxNode,
    SyntaxKind::{self, WHITESPACE, COMMA, R_CURLY, R_PAREN, R_BRACK},
    algo::find_covering_node,
    ast,
};
use ra_fmt::{
    compute_ws, extract_trivial_expression
};
use crate::{
    LocalEdit, TextEditBuilder,
};

pub fn join_lines(file: &SourceFile, range: TextRange) -> LocalEdit {
    let range = if range.is_empty() {
        let syntax = file.syntax();
        let text = syntax.text().slice(range.start()..);
        let pos = match text.find('\n') {
            None => {
                return LocalEdit {
                    label: "join lines".to_string(),
                    edit: TextEditBuilder::default().finish(),
                    cursor_position: None,
                };
            }
            Some(pos) => pos,
        };
        TextRange::offset_len(range.start() + pos, TextUnit::of_char('\n'))
    } else {
        range
    };

    let node = find_covering_node(file.syntax(), range);
    let mut edit = TextEditBuilder::default();
    for node in node.descendants() {
        let text = match node.leaf_text() {
            Some(text) => text,
            None => continue,
        };
        let range = match range.intersection(&node.range()) {
            Some(range) => range,
            None => continue,
        } - node.range().start();
        for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
            let pos: TextUnit = (pos as u32).into();
            let off = node.range().start() + range.start() + pos;
            if !edit.invalidates_offset(off) {
                remove_newline(&mut edit, node, text.as_str(), off);
            }
        }
    }

    LocalEdit { label: "join lines".to_string(), edit: edit.finish(), cursor_position: None }
}

fn remove_newline(
    edit: &mut TextEditBuilder,
    node: &SyntaxNode,
    node_text: &str,
    offset: TextUnit,
) {
    if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 {
        // The node is either the first or the last in the file
        let suff = &node_text[TextRange::from_to(
            offset - node.range().start() + TextUnit::of_char('\n'),
            TextUnit::of_str(node_text),
        )];
        let spaces = suff.bytes().take_while(|&b| b == b' ').count();

        edit.replace(TextRange::offset_len(offset, ((spaces + 1) as u32).into()), " ".to_string());
        return;
    }

    // Special case that turns something like:
    //
    // ```
    // my_function({<|>
    //    <some-expr>
    // })
    // ```
    //
    // into `my_function(<some-expr>)`
    if join_single_expr_block(edit, node).is_some() {
        return;
    }
    // ditto for
    //
    // ```
    // use foo::{<|>
    //    bar
    // };
    // ```
    if join_single_use_tree(edit, node).is_some() {
        return;
    }

    // The node is between two other nodes
    let prev = node.prev_sibling().unwrap();
    let next = node.next_sibling().unwrap();
    if is_trailing_comma(prev.kind(), next.kind()) {
        // Removes: trailing comma, newline (incl. surrounding whitespace)
        edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
    } else if prev.kind() == COMMA && next.kind() == R_CURLY {
        // Removes: comma, newline (incl. surrounding whitespace)
        let space = if let Some(left) = prev.prev_sibling() { compute_ws(left, next) } else { " " };
        edit.replace(
            TextRange::from_to(prev.range().start(), node.range().end()),
            space.to_string(),
        );
    } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) {
        // Removes: newline (incl. surrounding whitespace), start of the next comment
        edit.delete(TextRange::from_to(
            node.range().start(),
            next.syntax().range().start() + TextUnit::of_str(next.prefix()),
        ));
    } else {
        // Remove newline but add a computed amount of whitespace characters
        edit.replace(node.range(), compute_ws(prev, next).to_string());
    }
}

fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
    let block = ast::Block::cast(node.parent()?)?;
    let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
    let expr = extract_trivial_expression(block)?;
    edit.replace(block_expr.syntax().range(), expr.syntax().text().to_string());
    Some(())
}

fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
    let use_tree_list = ast::UseTreeList::cast(node.parent()?)?;
    let (tree,) = use_tree_list.use_trees().collect_tuple()?;
    edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string());
    Some(())
}

fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
    match (left, right) {
        (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,
        _ => false,
    }
}

#[cfg(test)]
mod tests {
    use crate::test_utils::{assert_eq_text, check_action, extract_range};

    use super::*;

    fn check_join_lines(before: &str, after: &str) {
        check_action(before, after, |file, offset| {
            let range = TextRange::offset_len(offset, 0.into());
            let res = join_lines(file, range);
            Some(res)
        })
    }

    #[test]
    fn test_join_lines_comma() {
        check_join_lines(
            r"
fn foo() {
    <|>foo(1,
    )
}
",
            r"
fn foo() {
    <|>foo(1)
}
",
        );
    }

    #[test]
    fn test_join_lines_lambda_block() {
        check_join_lines(
            r"
pub fn reparse(&self, edit: &AtomTextEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| {
        self.full_reparse(edit)
    })
}
",
            r"
pub fn reparse(&self, edit: &AtomTextEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
}
",
        );
    }

    #[test]
    fn test_join_lines_block() {
        check_join_lines(
            r"
fn foo() {
    foo(<|>{
        92
    })
}",
            r"
fn foo() {
    foo(<|>92)
}",
        );
    }

    #[test]
    #[ignore] // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/868
    fn join_lines_adds_comma_for_block_in_match_arm() {
        check_join_lines(
            r"
fn foo(e: Result<U, V>) {
    match e {
        Ok(u) => <|>{
            u.foo()
        }
        Err(v) => v,
    }
}",
            r"
fn foo(e: Result<U, V>) {
    match e {
        Ok(u) => <|>u.foo(),
        Err(v) => v,
    }
}",
        );
    }

    #[test]
    fn test_join_lines_use_items_left() {
        // No space after the '{'
        check_join_lines(
            r"
<|>use ra_syntax::{
    TextUnit, TextRange,
};",
            r"
<|>use ra_syntax::{TextUnit, TextRange,
};",
        );
    }

    #[test]
    fn test_join_lines_use_items_right() {
        // No space after the '}'
        check_join_lines(
            r"
use ra_syntax::{
<|>    TextUnit, TextRange
};",
            r"
use ra_syntax::{
<|>    TextUnit, TextRange};",
        );
    }

    #[test]
    fn test_join_lines_use_items_right_comma() {
        // No space after the '}'
        check_join_lines(
            r"
use ra_syntax::{
<|>    TextUnit, TextRange,
};",
            r"
use ra_syntax::{
<|>    TextUnit, TextRange};",
        );
    }

    #[test]
    fn test_join_lines_use_tree() {
        check_join_lines(
            r"
use ra_syntax::{
    algo::<|>{
        find_leaf_at_offset,
    },
    ast,
};",
            r"
use ra_syntax::{
    algo::<|>find_leaf_at_offset,
    ast,
};",
        );
    }

    #[test]
    fn test_join_lines_normal_comments() {
        check_join_lines(
            r"
fn foo() {
    // Hello<|>
    // world!
}
",
            r"
fn foo() {
    // Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_doc_comments() {
        check_join_lines(
            r"
fn foo() {
    /// Hello<|>
    /// world!
}
",
            r"
fn foo() {
    /// Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_mod_comments() {
        check_join_lines(
            r"
fn foo() {
    //! Hello<|>
    //! world!
}
",
            r"
fn foo() {
    //! Hello<|> world!
}
",
        );
    }

    #[test]
    fn test_join_lines_multiline_comments_1() {
        check_join_lines(
            r"
fn foo() {
    // Hello<|>
    /* world! */
}
",
            r"
fn foo() {
    // Hello<|> world! */
}
",
        );
    }

    #[test]
    fn test_join_lines_multiline_comments_2() {
        check_join_lines(
            r"
fn foo() {
    // The<|>
    /* quick
    brown
    fox! */
}
",
            r"
fn foo() {
    // The<|> quick
    brown
    fox! */
}
",
        );
    }

    fn check_join_lines_sel(before: &str, after: &str) {
        let (sel, before) = extract_range(before);
        let file = SourceFile::parse(&before);
        let result = join_lines(&file, sel);
        let actual = result.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_join_lines_selection_fn_args() {
        check_join_lines_sel(
            r"
fn foo() {
    <|>foo(1,
        2,
        3,
    <|>)
}
    ",
            r"
fn foo() {
    foo(1, 2, 3)
}
    ",
        );
    }

    #[test]
    fn test_join_lines_selection_struct() {
        check_join_lines_sel(
            r"
struct Foo <|>{
    f: u32,
}<|>
    ",
            r"
struct Foo { f: u32 }
    ",
        );
    }

    #[test]
    fn test_join_lines_selection_dot_chain() {
        check_join_lines_sel(
            r"
fn foo() {
    join(<|>type_params.type_params()
            .filter_map(|it| it.name())
            .map(|it| it.text())<|>)
}",
            r"
fn foo() {
    join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()))
}",
        );
    }

    #[test]
    fn test_join_lines_selection_lambda_block_body() {
        check_join_lines_sel(
            r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| <|>{
            world.analysis().matching_brace(&file, offset).unwrap_or(offset)
        }<|>)
        .collect();
}",
            r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset))
        .collect();
}",
        );
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    use test::Bencher;
    use std::thread;
    use std::sync::mpsc::channel;

    use mio::{EventLoop, Handler, Sender};

    struct MyHandler {
        n: usize,
    }

    impl Handler for MyHandler {
        type Timeout = ();
         type Message = u32;

        fn notify(&mut self, event_loop: &mut EventLoop<MyHandler>, msg: u32) {
            if msg == 0 {
                event_loop.shutdown();
                return;
            }

            self.n += 1;
        }
    }

    fn mio_must_send(sender: &Sender<u32>, n: u32) {
        loop {
            // Send may return notify error, we must retry.
            if let Ok(_) = sender.send(n) {
                return;
            }
        }
    }

    #[bench]
    fn bench_mio_channel(b: &mut Bencher) {
        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();

        let t = thread::spawn(move || {
            let mut h = MyHandler { n: 0 };
            event_loop.run(&mut h).unwrap();
            h.n
        });

        let mut n1 = 0;
        b.iter(|| {
            n1 += 1;
            mio_must_send(&sender, 1);
        });

        mio_must_send(&sender, 0);

        let n2 = t.join().unwrap();
        assert_eq!(n1, n2);
    }

    #[bench]
    fn bench_thread_channel(b: &mut Bencher) {
        let (tx, rx) = channel();

        let t = thread::spawn(move || {
            let mut n2: usize = 0;
            loop {
                let n = rx.recv().unwrap();
                if n == 0 {
                    return n2;
                }
                n2 += 1;
            }
        });

        let mut n1 = 0;
        b.iter(|| {
            n1 += 1;
            tx.send(1).unwrap()
        });

        tx.send(0).unwrap();
        let n2 = t.join().unwrap();
        assert_eq!(n1, n2);
    }
}
<commit_msg>raftserver: format code.<commit_after>#[cfg(test)]
mod tests {
    use test::Bencher;
    use std::thread;
    use std::sync::mpsc::channel;

    use mio::{EventLoop, Handler, Sender};

    struct MyHandler {
        n: usize,
    }

    impl Handler for MyHandler {
        type Timeout = ();
        type Message = u32;

        fn notify(&mut self, event_loop: &mut EventLoop<MyHandler>, msg: u32) {
            if msg == 0 {
                event_loop.shutdown();
                return;
            }

            self.n += 1;
        }
    }

    fn mio_must_send(sender: &Sender<u32>, n: u32) {
        loop {
            // Send may return notify error, we must retry.
            if let Ok(_) = sender.send(n) {
                return;
            }
        }
    }

    #[bench]
    fn bench_mio_channel(b: &mut Bencher) {
        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();

        let t = thread::spawn(move || {
            let mut h = MyHandler { n: 0 };
            event_loop.run(&mut h).unwrap();
            h.n
        });

        let mut n1 = 0;
        b.iter(|| {
            n1 += 1;
            mio_must_send(&sender, 1);
        });

        mio_must_send(&sender, 0);

        let n2 = t.join().unwrap();
        assert_eq!(n1, n2);
    }

    #[bench]
    fn bench_thread_channel(b: &mut Bencher) {
        let (tx, rx) = channel();

        let t = thread::spawn(move || {
            let mut n2: usize = 0;
            loop {
                let n = rx.recv().unwrap();
                if n == 0 {
                    return n2;
                }
                n2 += 1;
            }
        });

        let mut n1 = 0;
        b.iter(|| {
            n1 += 1;
            tx.send(1).unwrap()
        });

        tx.send(0).unwrap();
        let n2 = t.join().unwrap();
        assert_eq!(n1, n2);
    }
}
<|endoftext|>