<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::marker::PhantomData;
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferSlice;
use format::StrongStorage;

use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents a way for the GPU to interpret buffer data.
///
/// Note that a buffer view is only required for some operations. For example using a buffer as a
/// uniform buffer doesn't require creating a `BufferView`.
pub struct BufferView<F, B> where B: Buffer {
    view: vk::BufferView,
    buffer: Arc<B>,
    marker: PhantomData<F>,
    atomic_accesses: bool,
}

impl<F, B> BufferView<F, B> where B: Buffer {
    /// Builds a new buffer view.
    ///
    /// The format of the view will be automatically determined by the `T` parameter.
    ///
    /// The buffer must have been created with either the `uniform_texel_buffer` or
    /// the `storage_texel_buffer` usage or an error will occur.
    pub fn new<'a, S>(buffer: S, format: F)
                      -> Result<Arc<BufferView<F, B>>, BufferViewCreationError>
        where S: Into<BufferSlice<'a, [F::Pixel], B>>, B: 'static, F: StrongStorage + 'static
    {
        let buffer = buffer.into();
        let device = buffer.resource.inner_buffer().device();
        let format = format.format();

        if !buffer.buffer().inner_buffer().usage_uniform_texel_buffer() &&
           !buffer.buffer().inner_buffer().usage_storage_texel_buffer()
        {
            return Err(BufferViewCreationError::WrongBufferUsage);
        }

        let format_props = unsafe {
            let vk_i = device.instance().pointers();
            let mut output = mem::uninitialized();
            vk_i.GetPhysicalDeviceFormatProperties(device.physical_device().internal_object(),
                                                   format as u32, &mut output);
            output.bufferFeatures
        };

        if buffer.buffer().inner_buffer().usage_uniform_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        if buffer.buffer().inner_buffer().usage_storage_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        let infos = vk::BufferViewCreateInfo {
            sType: vk::STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
            pNext: ptr::null(),
            flags: 0,   // reserved,
            buffer: buffer.resource.inner_buffer().internal_object(),
            format: format as u32,
            offset: buffer.offset as u64,
            range: buffer.size as u64,
        };

        let view = unsafe {
            let vk = device.pointers();
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateBufferView(device.internal_object(), &infos,
                                                  ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(BufferView {
            view: view,
            buffer: buffer.resource.clone(),
            marker: PhantomData,
            atomic_accesses: (format_props &
                              vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) != 0,
        }))
    }

    /// Returns true if the buffer view can be used as a uniform texel buffer.
    #[inline]
    pub fn uniform_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_uniform_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer.
    #[inline]
    pub fn storage_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_storage_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses.
    #[inline]
    pub fn storage_texel_buffer_atomic(&self) -> bool {
        self.atomic_accesses && self.storage_texel_buffer()
    }
}

unsafe impl<F, B> VulkanObject for BufferView<F, B> where B: Buffer {
    type Object = vk::BufferView;

    #[inline]
    fn internal_object(&self) -> vk::BufferView {
        self.view
    }
}

impl<F, B> Drop for BufferView<F, B> where B: Buffer {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.buffer.inner_buffer().device().pointers();
            vk.DestroyBufferView(self.buffer.inner_buffer().device().internal_object(), self.view,
                                 ptr::null());
        }
    }
}

/// Error that can happen when creating a buffer view.
#[derive(Debug, Copy, Clone)]
pub enum BufferViewCreationError {
    /// Out of memory.
    OomError(OomError),

    /// The buffer was not creating with one of the `storage_texel_buffer` or
    /// `uniform_texel_buffer` usages.
    WrongBufferUsage,

    /// The requested format is not supported for this usage.
    UnsupportedFormat,
}

impl error::Error for BufferViewCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            BufferViewCreationError::OomError(_) => "out of memory when creating buffer view",
            BufferViewCreationError::WrongBufferUsage => "the buffer is missing correct usage \
                                                          flags",
            BufferViewCreationError::UnsupportedFormat => "the requested format is not supported \
                                                           for this usage",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            BufferViewCreationError::OomError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for BufferViewCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for BufferViewCreationError {
    #[inline]
    fn from(err: OomError) -> BufferViewCreationError {
        BufferViewCreationError::OomError(err)
    }
}

impl From<Error> for BufferViewCreationError {
    #[inline]
    fn from(err: Error) -> BufferViewCreationError {
        OomError::from(err).into()
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufferView;
    use buffer::sys::Usage;
    use buffer::view::BufferViewCreationError;
    use buffer::immutable::ImmutableBuffer;
    use format;

    #[test]
    fn create_uniform() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.uniform_texel_buffer());
    }

    #[test]
    fn create_storage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.storage_texel_buffer());
    }

    #[test]
    fn create_storage_atomic() {
        // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[u32]>::array(&device, 128, &usage,
                                                     Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R32Uint).unwrap();

        assert!(view.storage_texel_buffer());
        assert!(view.storage_texel_buffer_atomic());
    }

    #[test]
    fn wrong_usage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &Usage::none(),
                                                         Some(queue.family())).unwrap();

        match BufferView::new(&buffer, format::R8G8B8A8Unorm) {
            Err(BufferViewCreationError::WrongBufferUsage) => (),
            _ => panic!()
        }
    }

    #[test]
    fn unsupported_format() {
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[f64; 4]]>::array(&device, 128, &usage,
                                                          Some(queue.family())).unwrap();

        // TODO: what if R64G64B64A64Sfloat is supported?
        match BufferView::new(&buffer, format::R64G64B64A64Sfloat) {
            Err(BufferViewCreationError::UnsupportedFormat) => (),
            _ => panic!()
        }
    }
}
<commit_msg>Add docs and minor improvements in buffer view<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.

//! View of a buffer, in order to use it as a uniform texel buffer or storage texel buffer.
//!
//! In order to use a buffer as a uniform texel buffer or a storage texel buffer, you have to
//! create a `BufferView`, which indicates which format the data is in.
//!
//! In order to create a view from a buffer, the buffer must have been created with either the
//! `uniform_texel_buffer` or the `storage_texel_buffer` usage.
//!
//! # Example
//!
//! ```
//! use vulkano::buffer::sys::Usage;
//! use vulkano::format;
//!
//! # let (device, queue) = gfx_dev_and_queue!();
//! let usage = Usage {
//!     storage_texel_buffer: true,
//!     .. Usage::none()
//! };
//!
//! let buffer = ImmutableBuffer::<[u32]>::array(&device, 128, &usage,
//!                                              Some(queue.family())).unwrap();
//! let _view = BufferView::new(&buffer, format::R32Uint).unwrap();
//! ```

use std::marker::PhantomData;
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferSlice;
use format::FormatDesc;
use format::StrongStorage;

use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents a way for the GPU to interpret buffer data. See the documentation of the
/// `view` module.
pub struct BufferView<F, B> where B: Buffer {
    view: vk::BufferView,
    buffer: Arc<B>,
    marker: PhantomData<F>,
    atomic_accesses: bool,
}

impl<F, B> BufferView<F, B> where B: Buffer {
    /// Builds a new buffer view.
    #[inline]
    pub fn new<'a, S>(buffer: S, format: F)
                      -> Result<Arc<BufferView<F, B>>, BufferViewCreationError>
        where S: Into<BufferSlice<'a, [F::Pixel], B>>, B: 'static, F: StrongStorage + 'static
    {
        unsafe {
            BufferView::unchecked(buffer, format)
        }
    }

    /// Builds a new buffer view without checking that the format is correct.
    pub unsafe fn unchecked<'a, S, T: ?Sized>(buffer: S, format: F)
                                              -> Result<Arc<BufferView<F, B>>,
                                                        BufferViewCreationError>
        where S: Into<BufferSlice<'a, T, B>>, B: 'static, T: 'static, F: FormatDesc + 'static
    {
        let buffer = buffer.into();
        let device = buffer.resource.inner_buffer().device();
        let format = format.format();

        if !buffer.buffer().inner_buffer().usage_uniform_texel_buffer() &&
           !buffer.buffer().inner_buffer().usage_storage_texel_buffer()
        {
            return Err(BufferViewCreationError::WrongBufferUsage);
        }

        let format_props = {
            let vk_i = device.instance().pointers();
            let mut output = mem::uninitialized();
            vk_i.GetPhysicalDeviceFormatProperties(device.physical_device().internal_object(),
                                                   format as u32, &mut output);
            output.bufferFeatures
        };

        if buffer.buffer().inner_buffer().usage_uniform_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        if buffer.buffer().inner_buffer().usage_storage_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        let infos = vk::BufferViewCreateInfo {
            sType: vk::STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
            pNext: ptr::null(),
            flags: 0,   // reserved,
            buffer: buffer.resource.inner_buffer().internal_object(),
            format: format as u32,
            offset: buffer.offset as u64,
            range: buffer.size as u64,
        };

        let view = {
            let vk = device.pointers();
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateBufferView(device.internal_object(), &infos,
                                                  ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(BufferView {
            view: view,
            buffer: buffer.resource.clone(),
            marker: PhantomData,
            atomic_accesses: (format_props &
                              vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) != 0,
        }))
    }

    /// Returns true if the buffer view can be used as a uniform texel buffer.
    #[inline]
    pub fn uniform_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_uniform_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer.
    #[inline]
    pub fn storage_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_storage_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses.
    #[inline]
    pub fn storage_texel_buffer_atomic(&self) -> bool {
        self.atomic_accesses && self.storage_texel_buffer()
    }
}

unsafe impl<F, B> VulkanObject for BufferView<F, B> where B: Buffer {
    type Object = vk::BufferView;

    #[inline]
    fn internal_object(&self) -> vk::BufferView {
        self.view
    }
}

impl<F, B> Drop for BufferView<F, B> where B: Buffer {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.buffer.inner_buffer().device().pointers();
            vk.DestroyBufferView(self.buffer.inner_buffer().device().internal_object(), self.view,
                                 ptr::null());
        }
    }
}

/// Error that can happen when creating a buffer view.
#[derive(Debug, Copy, Clone)]
pub enum BufferViewCreationError {
    /// Out of memory.
    OomError(OomError),

    /// The buffer was not creating with one of the `storage_texel_buffer` or
    /// `uniform_texel_buffer` usages.
    WrongBufferUsage,

    /// The requested format is not supported for this usage.
    UnsupportedFormat,
}

impl error::Error for BufferViewCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            BufferViewCreationError::OomError(_) => "out of memory when creating buffer view",
            BufferViewCreationError::WrongBufferUsage => "the buffer is missing correct usage \
                                                          flags",
            BufferViewCreationError::UnsupportedFormat => "the requested format is not supported \
                                                           for this usage",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            BufferViewCreationError::OomError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for BufferViewCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for BufferViewCreationError {
    #[inline]
    fn from(err: OomError) -> BufferViewCreationError {
        BufferViewCreationError::OomError(err)
    }
}

impl From<Error> for BufferViewCreationError {
    #[inline]
    fn from(err: Error) -> BufferViewCreationError {
        OomError::from(err).into()
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufferView;
    use buffer::sys::Usage;
    use buffer::view::BufferViewCreationError;
    use buffer::immutable::ImmutableBuffer;
    use format;

    #[test]
    fn create_uniform() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.uniform_texel_buffer());
    }

    #[test]
    fn create_storage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.storage_texel_buffer());
    }

    #[test]
    fn create_storage_atomic() {
        // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[u32]>::array(&device, 128, &usage,
                                                     Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R32Uint).unwrap();

        assert!(view.storage_texel_buffer());
        assert!(view.storage_texel_buffer_atomic());
    }

    #[test]
    fn wrong_usage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &Usage::none(),
                                                         Some(queue.family())).unwrap();

        match BufferView::new(&buffer, format::R8G8B8A8Unorm) {
            Err(BufferViewCreationError::WrongBufferUsage) => (),
            _ => panic!()
        }
    }

    #[test]
    fn unsupported_format() {
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[f64; 4]]>::array(&device, 128, &usage,
                                                          Some(queue.family())).unwrap();

        // TODO: what if R64G64B64A64Sfloat is supported?
        match BufferView::new(&buffer, format::R64G64B64A64Sfloat) {
            Err(BufferViewCreationError::UnsupportedFormat) => (),
            _ => panic!()
        }
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{
    SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF},
};

use crate::assists::{AssistCtx, Assist};

pub fn change_visibility(ctx: AssistCtx) -> Option<Assist> {
    let keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() {
        FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
        _ => false,
    })?;
    let parent = keyword.parent()?;
    let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
    // Parent is not a definition, can't add visibility
    if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
        return None;
    }
    // Already have visibility, do nothing
    if parent.children().any(|child| child.kind() == VISIBILITY) {
        return None;
    }

    let node_start = parent.range().start();
    ctx.build("make pub crate", |edit| {
        edit.insert(node_start, "pub(crate) ");
        edit.set_cursor(node_start);
    })
}

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

    #[test]
    fn test_change_visibility() {
        check_assist(
            change_visibility,
            "<|>fn foo() {}",
            "<|>pub(crate) fn foo() {}",
        );
        check_assist(
            change_visibility,
            "f<|>n foo() {}",
            "<|>pub(crate) fn foo() {}",
        );
        check_assist(
            change_visibility,
            "<|>struct Foo {}",
            "<|>pub(crate) struct Foo {}",
        );
        check_assist(
            change_visibility,
            "<|>mod foo {}",
            "<|>pub(crate) mod foo {}",
        );
        check_assist(
            change_visibility,
            "<|>trait Foo {}",
            "<|>pub(crate) trait Foo {}",
        );
        check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
        check_assist(
            change_visibility,
            "unsafe f<|>n foo() {}",
            "<|>pub(crate) unsafe fn foo() {}",
        );
    }
}
<commit_msg>add pub(crate) works for named fields<commit_after>use ra_syntax::{
    AstNode,
    ast::{self, VisibilityOwner, NameOwner},
    SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF, IDENT},
};

use crate::assists::{AssistCtx, Assist};

pub fn change_visibility(ctx: AssistCtx) -> Option<Assist> {
    let offset = if let Some(keyword) = ctx.leaf_at_offset().find(|leaf| match leaf.kind() {
        FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
        _ => false,
    }) {
        let parent = keyword.parent()?;
        let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
        // Parent is not a definition, can't add visibility
        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
            return None;
        }
        // Already have visibility, do nothing
        if parent.children().any(|child| child.kind() == VISIBILITY) {
            return None;
        }
        parent.range().start()
    } else {
        let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?;
        let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?;
        if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
            return None;
        }
        field.syntax().range().start()
    };

    ctx.build("make pub(crate)", |edit| {
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

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

    #[test]
    fn change_visibility_adds_pub_crate_to_items() {
        check_assist(
            change_visibility,
            "<|>fn foo() {}",
            "<|>pub(crate) fn foo() {}",
        );
        check_assist(
            change_visibility,
            "f<|>n foo() {}",
            "<|>pub(crate) fn foo() {}",
        );
        check_assist(
            change_visibility,
            "<|>struct Foo {}",
            "<|>pub(crate) struct Foo {}",
        );
        check_assist(
            change_visibility,
            "<|>mod foo {}",
            "<|>pub(crate) mod foo {}",
        );
        check_assist(
            change_visibility,
            "<|>trait Foo {}",
            "<|>pub(crate) trait Foo {}",
        );
        check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
        check_assist(
            change_visibility,
            "unsafe f<|>n foo() {}",
            "<|>pub(crate) unsafe fn foo() {}",
        );
    }

    #[test]
    fn change_visibility_works_with_struct_fields() {
        check_assist(
            change_visibility,
            "struct S { <|>field: u32 }",
            "struct S { <|>pub(crate) field: u32 }",
        )
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    notification::{Notification, ShowMessage},
    request::{Request, Shutdown},
    ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
    TextDocumentIdentifier, TextDocumentItem, Url,
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use test_utils::{find_mismatch, parse_fixture};
use thread_worker::Worker;

use ra_lsp_server::{main_loop, req, InitializationOptions};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |msg_receiver, msg_sender| {
                main_loop(
                    roots,
                    ClientCapabilities {
                        workspace: None,
                        text_document: Some(TextDocumentClientCapabilities {
                            definition: Some(GotoCapability {
                                dynamic_registration: None,
                                link_support: Some(true),
                            }),
                            ..Default::default()
                        }),
                        window: None,
                        experimental: None,
                    },
                    InitializationOptions::default(),
                    &msg_receiver,
                    &msg_sender,
                )
                .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<commit_msg>fix tests<commit_after>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    notification::{Notification, ShowMessage},
    request::{Request, Shutdown},
    ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
    TextDocumentIdentifier, TextDocumentItem, Url,
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use test_utils::{find_mismatch, parse_fixture};
use thread_worker::Worker;

use ra_lsp_server::{main_loop, req, ServerConfig};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |msg_receiver, msg_sender| {
                main_loop(
                    roots,
                    ClientCapabilities {
                        workspace: None,
                        text_document: Some(TextDocumentClientCapabilities {
                            definition: Some(GotoCapability {
                                dynamic_registration: None,
                                link_support: Some(true),
                            }),
                            ..Default::default()
                        }),
                        window: None,
                        experimental: None,
                    },
                    ServerConfig::default(),
                    &msg_receiver,
                    &msg_sender,
                )
                .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<|endoftext|>


<commit_before>pub mod config;
pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn bindings(doc: &witx::Document) -> Bindings {
    let bs = doc
        .modules()
        .map(|m| {
            (
                m.name.as_str().to_owned(),
                m.funcs()
                    .map(|f| (f.name.as_str().to_owned(), hostcall_name(&m, &f)))
                    .collect(),
            )
        })
        .collect();
    Bindings::new(bs)
}

pub fn generate(
    doc: &witx::Document,
    ctx_type: &Ident,
    ctx_constructor: &TokenStream,
    wiggle_mod_path: &TokenStream,
    pre_hook: &TokenStream,
    post_hook: &TokenStream,
) -> TokenStream {
    let names = wiggle_generate::Names::new(ctx_type, quote!(lucet_wiggle));
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    { #pre_hook }
                    let memory = lucet_wiggle::runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    let r = super::#mod_name::#method_name(&ctx, &memory, #(#call_args),*);
                    { #post_hook }
                    match r {
                        Ok(r) => { r },
                        Err(e) => { lucet_runtime::lucet_hostcall_terminate!(e); }
                    }
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        pub mod hostcalls {
            use lucet_runtime::lucet_hostcall;
            use super::#ctx_type;
            use #wiggle_mod_path::types::*;
            #(#fs)*
            /// Lucet-runtime expects hostcalls to be resolved by the runtime
            /// linker (dlopen). By calling `init` in your program, we ensure that
            /// each hostcall is reachable and not garbage-collected by the
            /// compile-time linker (ld).
            pub fn init() {
                let funcs: &[*const extern "C" fn()] = &[
                    #(#init),*
                ];
                for func in funcs {
                    assert_ne!(*func, std::ptr::null(), "hostcall address is not null");
                }
            }
        }
    }
}
<commit_msg>i made a bug<commit_after>pub mod config;
pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn bindings(doc: &witx::Document) -> Bindings {
    let bs = doc
        .modules()
        .map(|m| {
            (
                m.name.as_str().to_owned(),
                m.funcs()
                    .map(|f| (f.name.as_str().to_owned(), hostcall_name(&m, &f)))
                    .collect(),
            )
        })
        .collect();
    Bindings::new(bs)
}

pub fn generate(
    doc: &witx::Document,
    ctx_type: &Ident,
    ctx_constructor: &TokenStream,
    wiggle_mod_path: &TokenStream,
    pre_hook: &TokenStream,
    post_hook: &TokenStream,
) -> TokenStream {
    let names = wiggle_generate::Names::new(ctx_type, quote!(lucet_wiggle));
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    { #pre_hook }
                    let memory = lucet_wiggle::runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    let r = super::#mod_name::#method_name(&ctx, &memory, #(#call_args),*);
                    { #post_hook }
                    match r {
                        Ok(r) => { r },
                        Err(wiggle::Trap::String(s)) => { lucet_runtime::lucet_hostcall_terminate!(s); }
                        // I apologize for this load-bearing `as u32`.
                        // Wasi uses an u32 for the proc_exit status (`lucet_wasi::Exitcode`) in
                        // the witx. However, wasmtime::Trap exit status is an i32, so the
                        // wiggle::Trap::I32Exit variant mirrors Wasmtime. The value passed to
                        // lucet_hostcall_terminate gets Any-downcast back to an
                        // `lucet_wasi::Exitcode` when inspected in Wasi embeddings.
                        // On the upside, one day all of this code will be deleted and these sins
                        // will be washed away.
                        Err(wiggle::Trap::I32Exit(e)) => {
                            lucet_runtime::lucet_hostcall_terminate!(e as u32); }
                    }
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        pub mod hostcalls {
            use lucet_runtime::lucet_hostcall;
            use super::#ctx_type;
            use #wiggle_mod_path::types::*;
            #(#fs)*
            /// Lucet-runtime expects hostcalls to be resolved by the runtime
            /// linker (dlopen). By calling `init` in your program, we ensure that
            /// each hostcall is reachable and not garbage-collected by the
            /// compile-time linker (ld).
            pub fn init() {
                let funcs: &[*const extern "C" fn()] = &[
                    #(#init),*
                ];
                for func in funcs {
                    assert_ne!(*func, std::ptr::null(), "hostcall address is not null");
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use redox::{Box, String, Vec};

use super::avl;
use super::nvpair::NvList;
use super::vdev;
use super::zfs;

pub enum ImportType {
    Existing,
    Assemble,
}

// Storage pool allocator
pub struct Spa {
    name: String, // Pool name
    state: zfs::PoolState,
    load_state: zfs::SpaLoadState,
    root_vdev: vdev::Vdev,
}

impl Spa {
    // TODO
    /*pub fn create(name: String, config: NvList) -> Self {
        let root_vdev = vdev::Vdev::new();
        Self::new(name, root_vdev)
    }*/

    pub fn open(&mut self) -> zfs::Result<()> {
        let load_state = zfs::SpaLoadState::Open;
        if self.state == zfs::PoolState::Uninitialized {
            // First time opening

            self.activate();

            try!(self.load(load_state, ImportType::Existing, false));

        }

        Ok(())
    }

    fn new(name: String, root_vdev: vdev::Vdev) -> Self {
        Spa {
            name: name,
            state: zfs::PoolState::Uninitialized,
            load_state: zfs::SpaLoadState::None,
            root_vdev: root_vdev,
        }
    }

    fn load(&mut self, load_state: zfs::SpaLoadState,
            import_type: ImportType, mos_config: bool) -> zfs::Result<()> {
        let ref config = NvList::new(0); // TODO: this should be replaced by self.config

        let pool_guid = try!(config.get("pool_guid").ok_or(zfs::Error::Invalid));

        self.load_impl(pool_guid, config, load_state, import_type, mos_config);
        self.load_state = zfs::SpaLoadState::None;

        Ok(())
    }

    /// mosconfig: Whether `config` came from on-disk MOS and so is trusted, or was user-made and so
    /// is untrusted.
    fn load_impl(&mut self, pool_guid: u64, config: &NvList, load_state: zfs::SpaLoadState,
                 import_type: ImportType, mos_config: bool) -> zfs::Result<()> {
        self.load_state = load_state;

        // Parse the vdev tree config
        let nvroot = try!(config.get("vdev_tree").ok_or(zfs::Error::Invalid));
        let vdev_alloc_type =
            match import_type {
                ImportType::Existing => vdev::AllocType::Load,
                ImportType::Assemble => vdev::AllocType::Split,
            };
        let root_vdev = try!(self.parse_vdev_tree(nvroot, vdev_alloc_type));

        Ok(())
    }

    fn parse_vdev_tree(&mut self, nv: &NvList, alloc_type: vdev::AllocType) -> zfs::Result<vdev::Vdev> {
        let vdev = vdev::Vdev::load(nv, 0, alloc_type);

        // TODO: return here if the vdev is a leaf node

        // Get the vdev's children
        let children: &Vec<NvList> = try!(nv.get("children").ok_or(zfs::Error::Invalid));

        vdev
    }

    fn activate(&mut self) {
        assert!(self.state == zfs::PoolState::Uninitialized);

        self.state = zfs::PoolState::Active;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct SpaNamespace {
    // TODO: Use &str instead of String as key type. Lifetimes are hard.
    avl: avl::Tree<Spa, String>, // AVL tree of Spa sorted by name
}

impl SpaNamespace {
    pub fn new() -> Self {
        SpaNamespace {
            avl: avl::Tree::new(Box::new(|x| x.name.clone())),
        }
    }

    pub fn add(&mut self, spa: Spa) {
        self.avl.insert(spa);
    }

    pub fn find(&self, name: String) -> Option<&Spa> {
        self.avl.find(name)
    }

    pub fn find_mut(&mut self, name: String) -> Option<&mut Spa> {
        self.avl.find_mut(name)
    }
}
<commit_msg>spa stuff<commit_after>use redox::{Box, String, Vec};

use super::avl;
use super::nvpair::NvList;
use super::uberblock::Uberblock;
use super::vdev;
use super::zfs;

pub enum ImportType {
    Existing,
    Assemble,
}

// Storage pool allocator
pub struct Spa {
    name: String, // Pool name
    state: zfs::PoolState,
    load_state: zfs::SpaLoadState,
    root_vdev: vdev::Vdev,
    //ubsync: Uberblock, // Last synced uberblock
    //uberblock: Uberblock, // Current active uberblock
    did: u64, // if procp != p0, did of t1
}

impl Spa {
    // TODO
    /*pub fn create(name: String, config: NvList) -> Self {
        let root_vdev = vdev::Vdev::new();
        Self::new(name, root_vdev)
    }*/

    pub fn open(&mut self) -> zfs::Result<()> {
        let load_state = zfs::SpaLoadState::Open;
        if self.state == zfs::PoolState::Uninitialized {
            // First time opening

            self.activate();

            try!(self.load(load_state, ImportType::Existing, false));

        }

        Ok(())
    }

    fn new(name: String, root_vdev: vdev::Vdev) -> Self {
        Spa {
            name: name,
            state: zfs::PoolState::Uninitialized,
            load_state: zfs::SpaLoadState::None,
            root_vdev: root_vdev,
            did: 0,
        }
    }

    fn load(&mut self, load_state: zfs::SpaLoadState,
            import_type: ImportType, mos_config: bool) -> zfs::Result<()> {
        let ref config = NvList::new(0); // TODO: this should be replaced by self.config

        let pool_guid = try!(config.get("pool_guid").ok_or(zfs::Error::Invalid));

        self.load_impl(pool_guid, config, load_state, import_type, mos_config);
        self.load_state = zfs::SpaLoadState::None;

        Ok(())
    }

    /// mosconfig: Whether `config` came from on-disk MOS and so is trusted, or was user-made and so
    /// is untrusted.
    fn load_impl(&mut self, pool_guid: u64, config: &NvList, load_state: zfs::SpaLoadState,
                 import_type: ImportType, mos_config: bool) -> zfs::Result<()> {
        self.load_state = load_state;

        // Parse the vdev tree config
        let nvroot = try!(config.get("vdev_tree").ok_or(zfs::Error::Invalid));
        let vdev_alloc_type =
            match import_type {
                ImportType::Existing => vdev::AllocType::Load,
                ImportType::Assemble => vdev::AllocType::Split,
            };
        let root_vdev = try!(self.parse_vdev_tree(nvroot, vdev_alloc_type));

        Ok(())
    }

    fn parse_vdev_tree(&mut self, nv: &NvList, alloc_type: vdev::AllocType) -> zfs::Result<vdev::Vdev> {
        let vdev = vdev::Vdev::load(nv, 0, alloc_type);

        // TODO: return here if the vdev is a leaf node

        // Get the vdev's children
        let children: &Vec<NvList> = try!(nv.get("children").ok_or(zfs::Error::Invalid));

        vdev
    }

    fn activate(&mut self) {
        assert!(self.state == zfs::PoolState::Uninitialized);

        self.state = zfs::PoolState::Active;

        //self.normal_class = MetaslabClass::create(self, zfs_metaslab_ops);
        //self.log_class = MetaslabClass::create(self, zfs_metaslab_ops);

        self.did = 0;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct SpaNamespace {
    // TODO: Use &str instead of String as key type. Lifetimes are hard.
    avl: avl::Tree<Spa, String>, // AVL tree of Spa sorted by name
}

impl SpaNamespace {
    pub fn new() -> Self {
        SpaNamespace {
            avl: avl::Tree::new(Box::new(|x| x.name.clone())),
        }
    }

    pub fn add(&mut self, spa: Spa) {
        self.avl.insert(spa);
    }

    pub fn find(&self, name: String) -> Option<&Spa> {
        self.avl.find(name)
    }

    pub fn find_mut(&mut self, name: String) -> Option<&mut Spa> {
        self.avl.find_mut(name)
    }
}
<|endoftext|>


<commit_before>extern crate reqwest;
extern crate serde_json;
extern crate url;

use std::io::Write;

type BoxResult<T> = Result<T, Box<std::error::Error>>;

#[derive(Debug)]
struct OsmifyError {
    details: String
}

impl OsmifyError {
    fn new(msg: &str) -> OsmifyError {
        OsmifyError{details: msg.to_string()}
    }
}

impl std::fmt::Display for OsmifyError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl std::error::Error for OsmifyError {
    fn description(&self) -> &str {
        &self.details
    }
}

fn query_turbo(query: &str) -> BoxResult<String> {
    let url = "http://overpass-api.de/api/interpreter";

    let client = reqwest::Client::new();
    let body = String::from(query);
    let mut buf = client.post(url)
        .body(body)
        .send()?;
    Ok(buf.text()?)
}

fn query_nominatim(query: &str) -> BoxResult<String> {
    let prefix = "http://nominatim.openstreetmap.org/search.php?";
    let encoded: String = url::form_urlencoded::Serializer::new(String::new())
        .append_pair("q", query)
        .append_pair("format", "json")
        .finish();
    let url = format!("{}{}", prefix, encoded);

    let mut buf = reqwest::get(url.as_str())?;

    Ok(buf.text()?)
}

fn osmify(query: &str) -> BoxResult<String> {
    let nominatim = query_nominatim(query)?;
    let json: serde_json::Value = match serde_json::from_str(&nominatim) {
        Ok(value) => value,
        Err(error) => {
            return Err(Box::new(OsmifyError::new(&format!("Failed to parse JSON from nominatim: {:?}", error))));
        },
    };
    let mut elements = json.as_array().ok_or("option::NoneError")?.clone();
    if elements.is_empty() {
        return Err(Box::new(OsmifyError::new("No results from nominatim")));
    }

    if elements.len() > 1 {
        // There are multiple elements, prefer buildings if possible.
        let buildings: Vec<serde_json::Value> = elements.iter().filter(|i| {
            let i = match i.as_object() {
                Some(value) => value,
                None => return false,
            };
            let class = match i.get("class") {
                Some(value) => value.as_str(),
                None => return false,
            };
            match class {
                Some(value) => value == "building",
                None => false,
            }
        } ).map(|i| i.clone()).collect();

        if !buildings.is_empty() {
            elements = buildings;
        }
    }

    let element = elements[0].as_object().ok_or("option::NoneError")?;
    let lat = element["lat"].as_str().ok_or("option::NoneError")?;
    let lon = element["lon"].as_str().ok_or("option::NoneError")?;
    let object_type = element["osm_type"].as_str().ok_or("option::NoneError")?;
    let object_id = element["osm_id"].as_str().ok_or("option::NoneError")?;

    // Use overpass to get the properties of the object.
    let overpass_query = format!(r#"[out:json];
(
    {}({});
);
out body;"#, object_type, object_id);
    let turbo = query_turbo(&overpass_query)?;
    let json: serde_json::Value = match serde_json::from_str(&turbo) {
        Ok(value) => value,
        Err(error) => {
            return Err(Box::new(OsmifyError::new(&format!("Failed to parse JSON from overpass: {:?}", error))));
        },
    };
    let json = json.as_object().ok_or("option::NoneError")?;
    let elements = &json["elements"].as_array().ok_or("option::NoneError")?;
    if elements.is_empty() {
        return Err(Box::new(OsmifyError::new("No results from overpass")));
    }

    let element = &elements[0];
    let tags = element["tags"].as_object().ok_or("option::NoneError")?;
    let city = tags["addr:city"].as_str().ok_or("option::NoneError")?;
    let housenumber = tags["addr:housenumber"].as_str().ok_or("option::NoneError")?;
    let postcode = tags["addr:postcode"].as_str().ok_or("option::NoneError")?;
    let street = tags["addr:street"].as_str().ok_or("option::NoneError")?;
    let addr = format!("{} {}, {} {}", postcode, city, street, housenumber);

    // Print the result.
    Ok(String::from(format!("geo:{},{} ({})", lat, lon, addr)))
}

fn spinner(rx: std::sync::mpsc::Receiver<Result<String, String>>) -> BoxResult<()> {
    let spin_characters = vec!['\\', '|', '/', '-'];
    let mut spin_index = 0;
    loop {
        match rx.try_recv() {
            Ok(result) => {
                print!("\r");
                std::io::stdout().flush()?;
                let result = result?;
                println!("{}", result);
                return Ok(());
            },
            Err(_) => {
                print!("\r [{}] ", spin_characters[spin_index]);
                std::io::stdout().flush()?;
                spin_index = (spin_index + 1) % spin_characters.len();
                std::thread::sleep(std::time::Duration::from_millis(100));
            }
        }
    }
}

fn main() -> BoxResult<()> {
    let args: Vec<String> = std::env::args().collect();

    if args.len() > 1 {
        let (tx, rx) = std::sync::mpsc::channel();
        std::thread::spawn(move || {
            let result = osmify(&args[1]);
            match result {
                Ok(value) => tx.send(Ok(value)),
                Err(error) => tx.send(Err(format!("Failed to osmify: {:?}", error))),
            }
        });
        spinner(rx)?;
    } else {
        println!("usage: addr-osmify <query>");
        println!("");
        println!("e.g. addr-osmify 'Mészáros utca 58/a, Budapest'");
    }

    Ok(())
}
<commit_msg>addr-osmify-rust: license header<commit_after>/*
 * Copyright 2019 Miklos Vajna. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

extern crate reqwest;
extern crate serde_json;
extern crate url;

use std::io::Write;

type BoxResult<T> = Result<T, Box<std::error::Error>>;

#[derive(Debug)]
struct OsmifyError {
    details: String
}

impl OsmifyError {
    fn new(msg: &str) -> OsmifyError {
        OsmifyError{details: msg.to_string()}
    }
}

impl std::fmt::Display for OsmifyError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl std::error::Error for OsmifyError {
    fn description(&self) -> &str {
        &self.details
    }
}

fn query_turbo(query: &str) -> BoxResult<String> {
    let url = "http://overpass-api.de/api/interpreter";

    let client = reqwest::Client::new();
    let body = String::from(query);
    let mut buf = client.post(url)
        .body(body)
        .send()?;
    Ok(buf.text()?)
}

fn query_nominatim(query: &str) -> BoxResult<String> {
    let prefix = "http://nominatim.openstreetmap.org/search.php?";
    let encoded: String = url::form_urlencoded::Serializer::new(String::new())
        .append_pair("q", query)
        .append_pair("format", "json")
        .finish();
    let url = format!("{}{}", prefix, encoded);

    let mut buf = reqwest::get(url.as_str())?;

    Ok(buf.text()?)
}

fn osmify(query: &str) -> BoxResult<String> {
    let nominatim = query_nominatim(query)?;
    let json: serde_json::Value = match serde_json::from_str(&nominatim) {
        Ok(value) => value,
        Err(error) => {
            return Err(Box::new(OsmifyError::new(&format!("Failed to parse JSON from nominatim: {:?}", error))));
        },
    };
    let mut elements = json.as_array().ok_or("option::NoneError")?.clone();
    if elements.is_empty() {
        return Err(Box::new(OsmifyError::new("No results from nominatim")));
    }

    if elements.len() > 1 {
        // There are multiple elements, prefer buildings if possible.
        let buildings: Vec<serde_json::Value> = elements.iter().filter(|i| {
            let i = match i.as_object() {
                Some(value) => value,
                None => return false,
            };
            let class = match i.get("class") {
                Some(value) => value.as_str(),
                None => return false,
            };
            match class {
                Some(value) => value == "building",
                None => false,
            }
        } ).map(|i| i.clone()).collect();

        if !buildings.is_empty() {
            elements = buildings;
        }
    }

    let element = elements[0].as_object().ok_or("option::NoneError")?;
    let lat = element["lat"].as_str().ok_or("option::NoneError")?;
    let lon = element["lon"].as_str().ok_or("option::NoneError")?;
    let object_type = element["osm_type"].as_str().ok_or("option::NoneError")?;
    let object_id = element["osm_id"].as_str().ok_or("option::NoneError")?;

    // Use overpass to get the properties of the object.
    let overpass_query = format!(r#"[out:json];
(
    {}({});
);
out body;"#, object_type, object_id);
    let turbo = query_turbo(&overpass_query)?;
    let json: serde_json::Value = match serde_json::from_str(&turbo) {
        Ok(value) => value,
        Err(error) => {
            return Err(Box::new(OsmifyError::new(&format!("Failed to parse JSON from overpass: {:?}", error))));
        },
    };
    let json = json.as_object().ok_or("option::NoneError")?;
    let elements = &json["elements"].as_array().ok_or("option::NoneError")?;
    if elements.is_empty() {
        return Err(Box::new(OsmifyError::new("No results from overpass")));
    }

    let element = &elements[0];
    let tags = element["tags"].as_object().ok_or("option::NoneError")?;
    let city = tags["addr:city"].as_str().ok_or("option::NoneError")?;
    let housenumber = tags["addr:housenumber"].as_str().ok_or("option::NoneError")?;
    let postcode = tags["addr:postcode"].as_str().ok_or("option::NoneError")?;
    let street = tags["addr:street"].as_str().ok_or("option::NoneError")?;
    let addr = format!("{} {}, {} {}", postcode, city, street, housenumber);

    // Print the result.
    Ok(String::from(format!("geo:{},{} ({})", lat, lon, addr)))
}

fn spinner(rx: std::sync::mpsc::Receiver<Result<String, String>>) -> BoxResult<()> {
    let spin_characters = vec!['\\', '|', '/', '-'];
    let mut spin_index = 0;
    loop {
        match rx.try_recv() {
            Ok(result) => {
                print!("\r");
                std::io::stdout().flush()?;
                let result = result?;
                println!("{}", result);
                return Ok(());
            },
            Err(_) => {
                print!("\r [{}] ", spin_characters[spin_index]);
                std::io::stdout().flush()?;
                spin_index = (spin_index + 1) % spin_characters.len();
                std::thread::sleep(std::time::Duration::from_millis(100));
            }
        }
    }
}

fn main() -> BoxResult<()> {
    let args: Vec<String> = std::env::args().collect();

    if args.len() > 1 {
        let (tx, rx) = std::sync::mpsc::channel();
        std::thread::spawn(move || {
            let result = osmify(&args[1]);
            match result {
                Ok(value) => tx.send(Ok(value)),
                Err(error) => tx.send(Err(format!("Failed to osmify: {:?}", error))),
            }
        });
        spinner(rx)?;
    } else {
        println!("usage: addr-osmify <query>");
        println!("");
        println!("e.g. addr-osmify 'Mészáros utca 58/a, Budapest'");
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! An unbounded set of streams

use core::fmt::{self, Debug};
use core::iter::FromIterator;
use core::pin::Pin;

use futures_core::ready;
use futures_core::stream::{Stream, FusedStream};
use futures_core::task::{Context, Poll};

use super::assert_stream;
use crate::stream::{StreamExt, StreamFuture, FuturesUnordered};

/// An unbounded set of streams
///
/// This "combinator" provides the ability to maintain a set of streams
/// and drive them all to completion.
///
/// Streams are pushed into this set and their realized values are
/// yielded as they become ready. Streams will only be polled when they
/// generate notifications. This allows to coordinate a large number of streams.
///
/// Note that you can create a ready-made `SelectAll` via the
/// `select_all` function in the `stream` module, or you can start with an
/// empty set with the `SelectAll::new` constructor.
#[must_use = "streams do nothing unless polled"]
pub struct SelectAll<St> {
    inner: FuturesUnordered<StreamFuture<St>>,
}

impl<St: Debug> Debug for SelectAll<St> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "SelectAll {{ ... }}")
    }
}

impl<St: Stream + Unpin> SelectAll<St> {
    /// Constructs a new, empty `SelectAll`
    ///
    /// The returned `SelectAll` does not contain any streams and, in this
    /// state, `SelectAll::poll` will return `Poll::Ready(None)`.
    pub fn new() -> Self {
        Self { inner: FuturesUnordered::new() }
    }

    /// Returns the number of streams contained in the set.
    ///
    /// This represents the total number of in-flight streams.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns `true` if the set contains no streams
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Push a stream into the set.
    ///
    /// This function submits the given stream to the set for managing. This
    /// function will not call `poll` on the submitted stream. The caller must
    /// ensure that `SelectAll::poll` is called in order to receive task
    /// notifications.
    pub fn push(&mut self, stream: St) {
        self.inner.push(stream.into_future());
    }
}

impl<St: Stream + Unpin> Default for SelectAll<St> {
    fn default() -> Self {
        Self::new()
    }
}

impl<St: Stream + Unpin> Stream for SelectAll<St> {
    type Item = St::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        loop {
            match ready!(self.inner.poll_next_unpin(cx)) {
                Some((Some(item), remaining)) => {
                    self.push(remaining);
                    return Poll::Ready(Some(item));
                }
                Some((None, _)) => {
                    // `FuturesUnordered` thinks it isn't terminated
                    // because it yielded a Some.
                    // We do not return, but poll `FuturesUnordered`
                    // in the next loop iteration.
                }
                None => return Poll::Ready(None),
            }
        }
    }
}

impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
    fn is_terminated(&self) -> bool {
        self.inner.is_terminated()
    }
}

/// Convert a list of streams into a `Stream` of results from the streams.
///
/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
/// and bundles them together into a single stream.
/// The stream will yield items as they become available on the underlying
/// streams internally, in the order they become available.
///
/// Note that the returned set can also be used to dynamically push more
/// futures into the set as they become available.
///
/// This function is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Stream + Unpin
{
    let mut set = SelectAll::new();

    for stream in streams {
        set.push(stream);
    }

    assert_stream::<<I::Item as Stream>::Item, _>(set)
}

impl<St: Stream + Unpin> FromIterator<St> for SelectAll<St> {
    fn from_iter<T: IntoIterator<Item = St>>(iter: T) -> Self {
        select_all(iter)
    }
}

impl<St: Stream + Unpin> Extend<St> for SelectAll<St> {
    fn extend<T: IntoIterator<Item = St>>(&mut self, iter: T) {
        for st in iter {
            self.push(st)
        }
    }
}
<commit_msg>futures_util::stream::SelectAll::push should use &self. (#2293)<commit_after>//! An unbounded set of streams

use core::fmt::{self, Debug};
use core::iter::FromIterator;
use core::pin::Pin;

use futures_core::ready;
use futures_core::stream::{Stream, FusedStream};
use futures_core::task::{Context, Poll};

use super::assert_stream;
use crate::stream::{StreamExt, StreamFuture, FuturesUnordered};

/// An unbounded set of streams
///
/// This "combinator" provides the ability to maintain a set of streams
/// and drive them all to completion.
///
/// Streams are pushed into this set and their realized values are
/// yielded as they become ready. Streams will only be polled when they
/// generate notifications. This allows to coordinate a large number of streams.
///
/// Note that you can create a ready-made `SelectAll` via the
/// `select_all` function in the `stream` module, or you can start with an
/// empty set with the `SelectAll::new` constructor.
#[must_use = "streams do nothing unless polled"]
pub struct SelectAll<St> {
    inner: FuturesUnordered<StreamFuture<St>>,
}

impl<St: Debug> Debug for SelectAll<St> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "SelectAll {{ ... }}")
    }
}

impl<St: Stream + Unpin> SelectAll<St> {
    /// Constructs a new, empty `SelectAll`
    ///
    /// The returned `SelectAll` does not contain any streams and, in this
    /// state, `SelectAll::poll` will return `Poll::Ready(None)`.
    pub fn new() -> Self {
        Self { inner: FuturesUnordered::new() }
    }

    /// Returns the number of streams contained in the set.
    ///
    /// This represents the total number of in-flight streams.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Returns `true` if the set contains no streams
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    /// Push a stream into the set.
    ///
    /// This function submits the given stream to the set for managing. This
    /// function will not call `poll` on the submitted stream. The caller must
    /// ensure that `SelectAll::poll` is called in order to receive task
    /// notifications.
    pub fn push(&self, stream: St) {
        self.inner.push(stream.into_future());
    }
}

impl<St: Stream + Unpin> Default for SelectAll<St> {
    fn default() -> Self {
        Self::new()
    }
}

impl<St: Stream + Unpin> Stream for SelectAll<St> {
    type Item = St::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        loop {
            match ready!(self.inner.poll_next_unpin(cx)) {
                Some((Some(item), remaining)) => {
                    self.push(remaining);
                    return Poll::Ready(Some(item));
                }
                Some((None, _)) => {
                    // `FuturesUnordered` thinks it isn't terminated
                    // because it yielded a Some.
                    // We do not return, but poll `FuturesUnordered`
                    // in the next loop iteration.
                }
                None => return Poll::Ready(None),
            }
        }
    }
}

impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
    fn is_terminated(&self) -> bool {
        self.inner.is_terminated()
    }
}

/// Convert a list of streams into a `Stream` of results from the streams.
///
/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
/// and bundles them together into a single stream.
/// The stream will yield items as they become available on the underlying
/// streams internally, in the order they become available.
///
/// Note that the returned set can also be used to dynamically push more
/// futures into the set as they become available.
///
/// This function is only available when the `std` or `alloc` feature of this
/// library is activated, and it is activated by default.
pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
    where I: IntoIterator,
          I::Item: Stream + Unpin
{
    let set = SelectAll::new();

    for stream in streams {
        set.push(stream);
    }

    assert_stream::<<I::Item as Stream>::Item, _>(set)
}

impl<St: Stream + Unpin> FromIterator<St> for SelectAll<St> {
    fn from_iter<T: IntoIterator<Item = St>>(iter: T) -> Self {
        select_all(iter)
    }
}

impl<St: Stream + Unpin> Extend<St> for SelectAll<St> {
    fn extend<T: IntoIterator<Item = St>>(&mut self, iter: T) {
        for st in iter {
            self.push(st)
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, BufRead, BufReader, Cursor, Read, Seek, SeekFrom};
use std::path::Path;

use dynimage::DynamicImage;
use image::ImageFormat;
use {ImageError, ImageResult};

use super::free_functions;

/// A multi-format image reader.
///
/// Wraps an input reader to facilitate automatic detection of an image's format, appropriate
/// decoding method, and dispatches into the set of supported [`ImageDecoder`] implementations.
///
/// ## Usage
///
/// Opening a file, deducing the format automatically, and trying to decode the image contained can
/// be performed by constructing the reader and immediately consuming it. This guesses the format
/// based on the file content and falls back to the file path.
///
/// ```no_run
/// # use image::ImageError;
/// # use image::io::Reader;
/// # fn main() -> Result<(), ImageError> {
/// let image = Reader::open("path/to/image.png")?
///     .decode()?;
/// # Ok(()) }
/// ```
///
/// It is also make a guess based solely on the content. This is especially handy if the source is
/// some blob in memory and you have constructed the reader in another way. Here is an example with
/// a `pnm` black-and-white subformat that encodes its pixel matrix with ascii values.
///
/// ```no_run
/// # use image::ImageError;
/// # use image::io::Reader;
/// # fn main() -> Result<(), ImageError> {
/// use std::io::Cursor;
/// use image::ImageFormat;
///
/// let raw_data = b"P1 2 2\
///     0 1\
///     1 0";
///
/// let mut reader = Reader::new(Cursor::new(raw_data));
/// reader.guess_format().expect("Cursor io never fails");
/// assert_eq!(reader.format(), Some(ImageFormat::PNM));
///
/// let image = reader.decode()?;
/// # Ok(()) }
/// ```
///
/// As a final fallback or if only a specific format must be used, the reader always allows manual
/// specification of the supposed image format with [`set_format`].
///
/// [`set_format`]: #method.set_format
/// [`ImageDecoder`]: ../trait.ImageDecoder.html
pub struct Reader<R: Read> {
    /// The reader.
    inner: R,
    /// The format, if one has been set or deduced.
    format: Option<ImageFormat>,
}

impl<R: Read> Reader<R> {
    /// Create a new image reader without a preset format.
    ///
    /// It is possible to guess the format based on the content of the read object with
    /// [`guess_format`], or to set the format directly with [`set_format`].
    ///
    /// [`guess_format`]: #method.guess_format
    /// [`set_format`]: method.set_format
    pub fn new(reader: R) -> Self {
        Reader {
            inner: reader,
            format: None,
        }
    }

    /// Construct a reader with specified format.
    pub fn with_format(reader: R, format: ImageFormat) -> Self {
        Reader {
            inner: reader,
            format: Some(format),
        }
    }

    /// Get the currently determined format.
    pub fn format(&self) -> Option<ImageFormat> {
        self.format
    }

    /// Supply the format as which to interpret the read image.
    pub fn set_format(&mut self, format: ImageFormat) {
        self.format = Some(format);
    }

    /// Remove the current information on the image format.
    ///
    /// Note that many operations require format information to be present and will return e.g. an
    /// `ImageError::UnsupportedError` when the image format has not been set.
    pub fn clear_format(&mut self) {
        self.format = None;
    }

    /// Unwrap the reader.
    pub fn into_inner(self) -> R {
        self.inner
    }
}

impl Reader<BufReader<File>> {
    /// Open a file to read, format will be guessed from content or path.
    ///
    /// This will automatically begin reading the start of the file to determine the format, then
    /// fall back to the path. Use [`from_path`] to open a file but guess its format solely based
    /// on the path and not perform any io on the file yet.
    ///
    /// It is always possible to redetect the current format with [`guess_format`].
    ///
    /// [`from_path`]: #method.from_path
    /// [`guess_format`]: #method.guess_format
    pub fn open<P>(path: P) -> io::Result<Self> where P: AsRef<Path> {
        Self::open_impl(path.as_ref())
    }

    /// Open a file to read, format will be guessed from path.
    ///
    /// This will not attempt any io operation on the opened file.
    ///
    /// If you want to inspect the content for a better guess on the format, which does not depend
    /// on file extensions, use [`open`] instead.
    ///
    /// [`open`]: #method.open
    pub fn from_path<P>(path: P) -> io::Result<Self> where P: AsRef<Path> {
        Self::from_path_impl(path.as_ref())
    }

    fn open_impl(path: &Path) -> io::Result<Self> {
        let file = File::open(path)?;

        let mut reader = Reader {
            inner: BufReader::new(file),
            format: None,
        };

        reader.guess_format()?;

        if reader.format.is_none() {
            // If content didn't success, maybe guess the format based on path.
            if let Ok(format) = ImageFormat::from_path(path) {
                reader.format = Some(format);
            }
        }

        Ok(reader)
    }

    fn from_path_impl(path: &Path) -> io::Result<Self> {
        let file = File::open(path)?;
        Ok(Reader {
            inner: BufReader::new(file),
            format: ImageFormat::from_path(path).ok(),
        })
    }
}

impl<R: BufRead + Seek> Reader<R> {
    /// Replace the format with a guess based on the content.
    ///
    /// If the guess fails, the format is unchanged. Error is for seek, hence io::Error
    /// and not ImageError.
    pub fn guess_format(&mut self) -> io::Result<()> {
        let mut start = [0; 16];

        // Save current offset, read start, restore offset.
        let cur = self.inner.seek(SeekFrom::Current(0))?;
        let len = io::copy(
            // Accept shorter files but read at most 16 bytes.
            &mut self.inner.by_ref().take(16),
            &mut Cursor::new(&mut start[..]))?;
        self.inner.seek(SeekFrom::Start(cur))?;

        self.format = free_functions::guess_format(&start[..len as usize]).ok();
        Ok(())
    }

    /// Read the image dimensions.
    ///
    /// Uses the current format to construct the correct reader for the format.
    pub fn dimensions(mut self) -> ImageResult<(u32, u32)> {
        let format = self.require_format()?;
        free_functions::image_dimensions_with_format_impl(self.inner, format)
    }

    /// Read the image (replaces `load`).
    ///
    /// Uses the current format to construct the correct reader for the format.
    pub fn decode(mut self) -> ImageResult<DynamicImage> {
        let format = self.require_format()?;
        free_functions::load(self.inner, format)
    }

    fn require_format(&mut self) -> ImageResult<ImageFormat> {
        self.format.ok_or_else(||
            ImageError::UnsupportedError("Unable to determine image format".into()))
    }
}
<commit_msg>Align open with previous semantics<commit_after>use std::fs::File;
use std::io::{self, BufRead, BufReader, Cursor, Read, Seek, SeekFrom};
use std::path::Path;

use dynimage::DynamicImage;
use image::ImageFormat;
use {ImageError, ImageResult};

use super::free_functions;

/// A multi-format image reader.
///
/// Wraps an input reader to facilitate automatic detection of an image's format, appropriate
/// decoding method, and dispatches into the set of supported [`ImageDecoder`] implementations.
///
/// ## Usage
///
/// Opening a file, deducing the format based on the file path automatically, and trying to decode
/// the image contained can be performed by constructing the reader and immediately consuming it.
///
/// ```no_run
/// # use image::ImageError;
/// # use image::io::Reader;
/// # fn main() -> Result<(), ImageError> {
/// let image = Reader::open("path/to/image.png")?
///     .decode()?;
/// # Ok(()) }
/// ```
///
/// It is also possible to make a guess based on the content. This is especially handy if the
/// source is some blob in memory and you have constructed the reader in another way. Here is an
/// example with a `pnm` black-and-white subformat that encodes its pixel matrix with ascii values.
///
/// ```no_run
/// # use image::ImageError;
/// # use image::io::Reader;
/// # fn main() -> Result<(), ImageError> {
/// use std::io::Cursor;
/// use image::ImageFormat;
///
/// let raw_data = b"P1 2 2\
///     0 1\
///     1 0";
///
/// let mut reader = Reader::new(Cursor::new(raw_data));
/// reader.guess_format().expect("Cursor io never fails");
/// assert_eq!(reader.format(), Some(ImageFormat::PNM));
///
/// let image = reader.decode()?;
/// # Ok(()) }
/// ```
///
/// As a final fallback or if only a specific format must be used, the reader always allows manual
/// specification of the supposed image format with [`set_format`].
///
/// [`set_format`]: #method.set_format
/// [`ImageDecoder`]: ../trait.ImageDecoder.html
pub struct Reader<R: Read> {
    /// The reader.
    inner: R,
    /// The format, if one has been set or deduced.
    format: Option<ImageFormat>,
}

impl<R: Read> Reader<R> {
    /// Create a new image reader without a preset format.
    ///
    /// It is possible to guess the format based on the content of the read object with
    /// [`guess_format`], or to set the format directly with [`set_format`].
    ///
    /// [`guess_format`]: #method.guess_format
    /// [`set_format`]: method.set_format
    pub fn new(reader: R) -> Self {
        Reader {
            inner: reader,
            format: None,
        }
    }

    /// Construct a reader with specified format.
    pub fn with_format(reader: R, format: ImageFormat) -> Self {
        Reader {
            inner: reader,
            format: Some(format),
        }
    }

    /// Get the currently determined format.
    pub fn format(&self) -> Option<ImageFormat> {
        self.format
    }

    /// Supply the format as which to interpret the read image.
    pub fn set_format(&mut self, format: ImageFormat) {
        self.format = Some(format);
    }

    /// Remove the current information on the image format.
    ///
    /// Note that many operations require format information to be present and will return e.g. an
    /// `ImageError::UnsupportedError` when the image format has not been set.
    pub fn clear_format(&mut self) {
        self.format = None;
    }

    /// Unwrap the reader.
    pub fn into_inner(self) -> R {
        self.inner
    }
}

impl Reader<BufReader<File>> {
    /// Open a file to read, format will be guessed from path.
    ///
    /// This will not attempt any io operation on the opened file.
    ///
    /// If you want to inspect the content for a better guess on the format, which does not depend
    /// on file extensions, follow this call with a call to [`guess_format`].
    ///
    /// [`guess_format`]: #method.guess_format
    pub fn open<P>(path: P) -> io::Result<Self> where P: AsRef<Path> {
        Self::open_impl(path.as_ref())
    }

    fn open_impl(path: &Path) -> io::Result<Self> {
        let file = File::open(path)?;
        Ok(Reader {
            inner: BufReader::new(file),
            format: ImageFormat::from_path(path).ok(),
        })
    }
}

impl<R: BufRead + Seek> Reader<R> {
    /// Replace the format with a guess based on the content.
    ///
    /// If the guess fails, the format is unchanged. Error is for seek, hence io::Error
    /// and not ImageError.
    pub fn guess_format(&mut self) -> io::Result<()> {
        let mut start = [0; 16];

        // Save current offset, read start, restore offset.
        let cur = self.inner.seek(SeekFrom::Current(0))?;
        let len = io::copy(
            // Accept shorter files but read at most 16 bytes.
            &mut self.inner.by_ref().take(16),
            &mut Cursor::new(&mut start[..]))?;
        self.inner.seek(SeekFrom::Start(cur))?;

        if let Ok(format) = free_functions::guess_format(&start[..len as usize]) {
            self.format = Some(format);
        }
        Ok(())
    }

    /// Read the image dimensions.
    ///
    /// Uses the current format to construct the correct reader for the format.
    ///
    /// If no format was determined, returns an `ImageError::UnsupportedError`.
    pub fn dimensions(mut self) -> ImageResult<(u32, u32)> {
        let format = self.require_format()?;
        free_functions::image_dimensions_with_format_impl(self.inner, format)
    }

    /// Read the image (replaces `load`).
    ///
    /// Uses the current format to construct the correct reader for the format.
    ///
    /// If no format was determined, returns an `ImageError::UnsupportedError`.
    pub fn decode(mut self) -> ImageResult<DynamicImage> {
        let format = self.require_format()?;
        free_functions::load(self.inner, format)
    }

    fn require_format(&mut self) -> ImageResult<ImageFormat> {
        self.format.ok_or_else(||
            ImageError::UnsupportedError("Unable to determine image format".into()))
    }
}
<|endoftext|>