<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::any::Any;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use buffer::Buffer;
use command_buffer::states_manager::StatesManager;
use device::Queue;
use format::ClearValue;
use format::Format;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Fence;
use sync::Semaphore;

use VulkanObject;

/// Trait for types that represent images.
// TODO: remove 'static + Send + Sync
pub unsafe trait Image: 'static + Send + Sync {
    /// Returns the inner unsafe image object used by this image.
    fn inner(&self) -> &UnsafeImage;

    /// Returns the format of this image.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    /// Returns the number of samples of this image.
    #[inline]
    fn samples(&self) -> u32 {
        self.inner().samples()
    }

    /// Returns the dimensions of the image.
    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.inner().dimensions()
    }

    /// Returns true if the image can be used as a source for blits.
    #[inline]
    fn supports_blit_source(&self) -> bool {
        self.inner().supports_blit_source()
    }

    /// Returns true if the image can be used as a destination for blits.
    #[inline]
    fn supports_blit_destination(&self) -> bool {
        self.inner().supports_blit_destination()
    }
}

/// Extension trait for `Image`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedImage<States = StatesManager>: Image {
    /// Returns a new state that corresponds to the moment after a slice of the image has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    // TODO: what should be the behavior if `num_command` is equal to the `num_command` of a
    // previous transition?
    fn transition(&self, states: &mut States, num_command: usize, first_mipmap: u32,
                  num_mipmaps: u32, first_layer: u32, num_layers: u32, write: bool, layout: Layout,
                  stage: PipelineStages, access: AccessFlagBits) -> Option<PipelineBarrierRequest>;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(&self, in_s: &mut States, out: &mut States) -> Option<PipelineBarrierRequest>;

    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<F>(&self, states: &States, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>;
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the image hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the image that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    pub first_mipmap: u32,
    pub num_mipmaps: u32,
    pub first_layer: u32,
    pub num_layers: u32,

    pub old_layout: Layout,
    pub new_layout: Layout,

    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Receiver<Arc<Semaphore>>, PipelineStages)>,
    pub post_semaphore: Option<Sender<Arc<Semaphore>>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
/// given image.
// TODO: isn't that for image views instead?
pub unsafe trait ImageClearValue<T>: Image {
    fn decode(&self, T) -> Option<ClearValue>;
}

pub unsafe trait ImageContent<P>: Image {
    /// Checks whether pixels of type `P` match the format of the image.
    fn matches_format(&self) -> bool;
}

/// Trait for types that represent image views.
// TODO: remove 'static + Send + Sync
pub unsafe trait ImageView: 'static + Send + Sync {
    fn parent(&self) -> &Image;

    fn parent_arc(&Arc<Self>) -> Arc<Image> where Self: Sized;

    /// Returns the dimensions of the image view.
    fn dimensions(&self) -> Dimensions;

    /// Returns the inner unsafe image view object used by this image view.
    fn inner(&self) -> &UnsafeImageView;

    /// Returns the blocks of the parent image this image view overlaps.
    fn blocks(&self) -> Vec<(u32, u32)>;

    /// Returns the format of this view. This can be different from the parent's format.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.parent().samples()
    }

    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_storage_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_sampled_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_input_attachment_layout(&self) -> Layout;

    /// Returns true if the view doesn't use components swizzling.
    ///
    /// Must be true when the view is used as a framebuffer attachment or TODO: I don't remember
    /// the other thing.
    fn identity_swizzle(&self) -> bool;

    /// Returns true if the given sampler can be used with this image view.
    ///
    /// This method should check whether the sampler's configuration can be used with the format
    /// of the view.
    // TODO: return a Result
    fn can_be_sampled(&self, sampler: &Sampler) -> bool { true /* FIXME */ }

    //fn usable_as_render_pass_attachment(&self, ???) -> Result<(), ???>;
}

unsafe impl<T> ImageView for Arc<T> where T: ImageView {
    #[inline]
    fn parent(&self) -> &Image {
        (**self).parent()
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> {
        ImageView::parent_arc(&**me)
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        (**self).inner()
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        (**self).dimensions()
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        (**self).blocks()
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        (**self).descriptor_set_storage_image_layout()
    }
    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        (**self).descriptor_set_combined_image_sampler_layout()
    }
    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        (**self).descriptor_set_sampled_image_layout()
    }
    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        (**self).descriptor_set_input_attachment_layout()
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        (**self).identity_swizzle()
    }

    #[inline]
    fn can_be_sampled(&self, sampler: &Sampler) -> bool {
        (**self).can_be_sampled(sampler)
    }
}

pub unsafe trait TrackedImageView<States>: ImageView {
    type Image: TrackedImage<States>;

    fn image(&self) -> &Self::Image;
}

unsafe impl<States, T> TrackedImageView<States> for Arc<T> where T: TrackedImageView<States> {
    type Image = T::Image;

    #[inline]
    fn image(&self) -> &Self::Image {
        (**self).image()
    }
}

pub unsafe trait AttachmentImageView: ImageView {
    fn accept(&self, initial_layout: Layout, final_layout: Layout) -> bool;
}
<commit_msg>Remove 'static + Send + Sync from Image and ImageView traits<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::any::Any;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use buffer::Buffer;
use command_buffer::states_manager::StatesManager;
use device::Queue;
use format::ClearValue;
use format::Format;
use image::Dimensions;
use image::ImageDimensions;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use sampler::Sampler;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Fence;
use sync::Semaphore;

use VulkanObject;

/// Trait for types that represent images.
pub unsafe trait Image {
    /// Returns the inner unsafe image object used by this image.
    fn inner(&self) -> &UnsafeImage;

    /// Returns the format of this image.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    /// Returns the number of samples of this image.
    #[inline]
    fn samples(&self) -> u32 {
        self.inner().samples()
    }

    /// Returns the dimensions of the image.
    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.inner().dimensions()
    }

    /// Returns true if the image can be used as a source for blits.
    #[inline]
    fn supports_blit_source(&self) -> bool {
        self.inner().supports_blit_source()
    }

    /// Returns true if the image can be used as a destination for blits.
    #[inline]
    fn supports_blit_destination(&self) -> bool {
        self.inner().supports_blit_destination()
    }
}

/// Extension trait for `Image`. Types that implement this can be used in a `StdCommandBuffer`.
///
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
/// represented by the `CommandListState` associated type of this trait. You can make multiple
/// buffers or images share the same state by making `is_same` return true.
pub unsafe trait TrackedImage<States = StatesManager>: Image {
    /// Returns a new state that corresponds to the moment after a slice of the image has been
    /// used in the pipeline. The parameters indicate in which way it has been used.
    ///
    /// If the transition should result in a pipeline barrier, then it must be returned by this
    /// function.
    // TODO: what should be the behavior if `num_command` is equal to the `num_command` of a
    // previous transition?
    fn transition(&self, states: &mut States, num_command: usize, first_mipmap: u32,
                  num_mipmaps: u32, first_layer: u32, num_layers: u32, write: bool, layout: Layout,
                  stage: PipelineStages, access: AccessFlagBits) -> Option<PipelineBarrierRequest>;

    /// Function called when the command buffer builder is turned into a real command buffer.
    ///
    /// This function can return an additional pipeline barrier that will be applied at the end
    /// of the command buffer.
    fn finish(&self, in_s: &mut States, out: &mut States) -> Option<PipelineBarrierRequest>;

    /// Called right before the command buffer is submitted.
    // TODO: function should be unsafe because it must be guaranteed that a cb is submitted
    fn on_submit<F>(&self, states: &States, queue: &Arc<Queue>, fence: F) -> SubmitInfos
        where F: FnOnce() -> Arc<Fence>;
}

/// Requests that a pipeline barrier is created.
pub struct PipelineBarrierRequest {
    /// The number of the command after which the barrier should be placed. Must usually match
    /// the number that was passed to the previous call to `transition`, or 0 if the image hasn't
    /// been used yet.
    pub after_command_num: usize,

    /// The source pipeline stages of the transition.
    pub source_stage: PipelineStages,

    /// The destination pipeline stages of the transition.
    pub destination_stages: PipelineStages,

    /// If true, the pipeliner barrier is by region.
    pub by_region: bool,

    /// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
    pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
}

/// Requests that a memory barrier is created as part of the pipeline barrier.
///
/// By default, a pipeline barrier only guarantees that the source operations are executed before
/// the destination operations, but it doesn't make memory writes made by source operations visible
/// to the destination operations. In order to make so, you have to add a memory barrier.
///
/// The memory barrier always concerns the image that is currently being processed. You can't add
/// a memory barrier that concerns another resource.
pub struct PipelineMemoryBarrierRequest {
    pub first_mipmap: u32,
    pub num_mipmaps: u32,
    pub first_layer: u32,
    pub num_layers: u32,

    pub old_layout: Layout,
    pub new_layout: Layout,

    /// Source accesses.
    pub source_access: AccessFlagBits,
    /// Destination accesses.
    pub destination_access: AccessFlagBits,
}

pub struct SubmitInfos {
    pub pre_semaphore: Option<(Receiver<Arc<Semaphore>>, PipelineStages)>,
    pub post_semaphore: Option<Sender<Arc<Semaphore>>>,
    pub pre_barrier: Option<PipelineBarrierRequest>,
    pub post_barrier: Option<PipelineBarrierRequest>,
}

/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
/// given image.
// TODO: isn't that for image views instead?
pub unsafe trait ImageClearValue<T>: Image {
    fn decode(&self, T) -> Option<ClearValue>;
}

pub unsafe trait ImageContent<P>: Image {
    /// Checks whether pixels of type `P` match the format of the image.
    fn matches_format(&self) -> bool;
}

/// Trait for types that represent image views.
pub unsafe trait ImageView {
    fn parent(&self) -> &Image;

    fn parent_arc(&Arc<Self>) -> Arc<Image> where Self: Sized;

    /// Returns the dimensions of the image view.
    fn dimensions(&self) -> Dimensions;

    /// Returns the inner unsafe image view object used by this image view.
    fn inner(&self) -> &UnsafeImageView;

    /// Returns the blocks of the parent image this image view overlaps.
    fn blocks(&self) -> Vec<(u32, u32)>;

    /// Returns the format of this view. This can be different from the parent's format.
    #[inline]
    fn format(&self) -> Format {
        self.inner().format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.parent().samples()
    }

    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_storage_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_sampled_image_layout(&self) -> Layout;
    /// Returns the image layout to use in a descriptor with the given subresource.
    fn descriptor_set_input_attachment_layout(&self) -> Layout;

    /// Returns true if the view doesn't use components swizzling.
    ///
    /// Must be true when the view is used as a framebuffer attachment or TODO: I don't remember
    /// the other thing.
    fn identity_swizzle(&self) -> bool;

    /// Returns true if the given sampler can be used with this image view.
    ///
    /// This method should check whether the sampler's configuration can be used with the format
    /// of the view.
    // TODO: return a Result
    fn can_be_sampled(&self, sampler: &Sampler) -> bool { true /* FIXME */ }

    //fn usable_as_render_pass_attachment(&self, ???) -> Result<(), ???>;
}

unsafe impl<T> ImageView for Arc<T> where T: ImageView {
    #[inline]
    fn parent(&self) -> &Image {
        (**self).parent()
    }

    #[inline]
    fn parent_arc(me: &Arc<Self>) -> Arc<Image> {
        ImageView::parent_arc(&**me)
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        (**self).inner()
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        (**self).dimensions()
    }

    #[inline]
    fn blocks(&self) -> Vec<(u32, u32)> {
        (**self).blocks()
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        (**self).descriptor_set_storage_image_layout()
    }
    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        (**self).descriptor_set_combined_image_sampler_layout()
    }
    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        (**self).descriptor_set_sampled_image_layout()
    }
    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        (**self).descriptor_set_input_attachment_layout()
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        (**self).identity_swizzle()
    }

    #[inline]
    fn can_be_sampled(&self, sampler: &Sampler) -> bool {
        (**self).can_be_sampled(sampler)
    }
}

pub unsafe trait TrackedImageView<States>: ImageView {
    type Image: TrackedImage<States>;

    fn image(&self) -> &Self::Image;
}

unsafe impl<States, T> TrackedImageView<States> for Arc<T> where T: TrackedImageView<States> {
    type Image = T::Image;

    #[inline]
    fn image(&self) -> &Self::Image {
        (**self).image()
    }
}

pub unsafe trait AttachmentImageView: ImageView {
    fn accept(&self, initial_layout: Layout, final_layout: Layout) -> bool;
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use hir::{Semantics, SemanticsScope};
use ra_db::SourceDatabase;
use ra_ide_db::RootDatabase;
use ra_syntax::{
    algo::{find_covering_element, find_node_at_offset},
    ast, AstNode,
    SyntaxKind::*,
    SyntaxNode, SyntaxToken, TextRange, TextUnit,
};
use ra_text_edit::AtomTextEdit;

use crate::{call_info::call_info, completion::CompletionConfig, CallInfo, FilePosition};

/// `CompletionContext` is created early during completion to figure out, where
/// exactly is the cursor, syntax-wise.
#[derive(Debug)]
pub(crate) struct CompletionContext<'a> {
    pub(super) sema: Semantics<'a, RootDatabase>,
    pub(super) db: &'a RootDatabase,
    pub(super) config: &'a CompletionConfig,
    pub(super) offset: TextUnit,
    pub(super) file_position: FilePosition,
    /// The token before the cursor, in the original file.
    pub(super) original_token: SyntaxToken,
    /// The token before the cursor, in the macro-expanded file.
    pub(super) token: SyntaxToken,
    pub(super) krate: Option<hir::Crate>,
    pub(super) name_ref_syntax: Option<ast::NameRef>,
    pub(super) function_syntax: Option<ast::FnDef>,
    pub(super) use_item_syntax: Option<ast::UseItem>,
    pub(super) record_lit_syntax: Option<ast::RecordLit>,
    pub(super) record_pat_syntax: Option<ast::RecordPat>,
    pub(super) record_field_syntax: Option<ast::RecordField>,
    pub(super) impl_def: Option<ast::ImplDef>,
    pub(super) call_info: Option<CallInfo>,
    pub(super) is_param: bool,
    /// If a name-binding or reference to a const in a pattern.
    /// Irrefutable patterns (like let) are excluded.
    pub(super) is_pat_binding_or_const: bool,
    /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
    pub(super) is_trivial_path: bool,
    /// If not a trivial path, the prefix (qualifier).
    pub(super) path_prefix: Option<hir::Path>,
    pub(super) after_if: bool,
    /// `true` if we are a statement or a last expr in the block.
    pub(super) can_be_stmt: bool,
    /// Something is typed at the "top" level, in module or impl/trait.
    pub(super) is_new_item: bool,
    /// The receiver if this is a field or method access, i.e. writing something.<|>
    pub(super) dot_receiver: Option<ast::Expr>,
    pub(super) dot_receiver_is_ambiguous_float_literal: bool,
    /// If this is a call (method or function) in particular, i.e. the () are already there.
    pub(super) is_call: bool,
    /// If this is a macro call, i.e. the () are already there.
    pub(super) is_macro_call: bool,
    pub(super) is_path_type: bool,
    pub(super) has_type_args: bool,
}

impl<'a> CompletionContext<'a> {
    pub(super) fn new(
        db: &'a RootDatabase,
        position: FilePosition,
        config: &'a CompletionConfig,
    ) -> Option<CompletionContext<'a>> {
        let sema = Semantics::new(db);

        let original_file = sema.parse(position.file_id);

        // Insert a fake ident to get a valid parse tree. We will use this file
        // to determine context, though the original_file will be used for
        // actual completion.
        let file_with_fake_ident = {
            let parse = db.parse(position.file_id);
            let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string());
            parse.reparse(&edit).tree()
        };
        let fake_ident_token =
            file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap();

        let krate = sema.to_module_def(position.file_id).map(|m| m.krate());
        let original_token =
            original_file.syntax().token_at_offset(position.offset).left_biased()?;
        let token = sema.descend_into_macros(original_token.clone());
        let mut ctx = CompletionContext {
            sema,
            db,
            config,
            original_token,
            token,
            offset: position.offset,
            file_position: position,
            krate,
            name_ref_syntax: None,
            function_syntax: None,
            call_info: None,
            use_item_syntax: None,
            record_lit_syntax: None,
            record_pat_syntax: None,
            record_field_syntax: None,
            impl_def: None,
            is_param: false,
            is_pat_binding_or_const: false,
            is_trivial_path: false,
            path_prefix: None,
            after_if: false,
            can_be_stmt: false,
            is_new_item: false,
            dot_receiver: None,
            is_call: false,
            is_macro_call: false,
            is_path_type: false,
            has_type_args: false,
            dot_receiver_is_ambiguous_float_literal: false,
        };

        let mut original_file = original_file.syntax().clone();
        let mut hypothetical_file = file_with_fake_ident.syntax().clone();
        let mut offset = position.offset;
        let mut fake_ident_token = fake_ident_token;

        // Are we inside a macro call?
        while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
            find_node_at_offset::<ast::MacroCall>(&original_file, offset),
            find_node_at_offset::<ast::MacroCall>(&hypothetical_file, offset),
        ) {
            if actual_macro_call.path().as_ref().map(|s| s.syntax().text())
                != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text())
            {
                break;
            }
            let hypothetical_args = match macro_call_with_fake_ident.token_tree() {
                Some(tt) => tt,
                None => break,
            };
            if let (Some(actual_expansion), Some(hypothetical_expansion)) = (
                ctx.sema.expand(&actual_macro_call),
                ctx.sema.expand_hypothetical(
                    &actual_macro_call,
                    &hypothetical_args,
                    fake_ident_token,
                ),
            ) {
                let new_offset = hypothetical_expansion.1.text_range().start();
                if new_offset > actual_expansion.text_range().end() {
                    break;
                }
                original_file = actual_expansion;
                hypothetical_file = hypothetical_expansion.0;
                fake_ident_token = hypothetical_expansion.1;
                offset = new_offset;
            } else {
                break;
            }
        }

        ctx.fill(&original_file, hypothetical_file, offset);
        Some(ctx)
    }

    // The range of the identifier that is being completed.
    pub(crate) fn source_range(&self) -> TextRange {
        // check kind of macro-expanded token, but use range of original token
        match self.token.kind() {
            // workaroud when completion is triggered by trigger characters.
            IDENT => self.original_token.text_range(),
            _ => TextRange::offset_len(self.offset, 0.into()),
        }
    }

    pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> {
        self.sema.scope_at_offset(&self.token.parent(), self.offset)
    }

    fn fill(
        &mut self,
        original_file: &SyntaxNode,
        file_with_fake_ident: SyntaxNode,
        offset: TextUnit,
    ) {
        // First, let's try to complete a reference to some declaration.
        if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
            // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
            // See RFC#1685.
            if is_node::<ast::Param>(name_ref.syntax()) {
                self.is_param = true;
                return;
            }
            // FIXME: remove this (V) duplication and make the check more precise
            if name_ref.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
                self.record_pat_syntax =
                    self.sema.find_node_at_offset_with_macros(&original_file, offset);
            }
            self.classify_name_ref(original_file, name_ref, offset);
        }

        // Otherwise, see if this is a declaration. We can use heuristics to
        // suggest declaration names, see `CompletionKind::Magic`.
        if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
            if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
                self.is_pat_binding_or_const = true;
                if bind_pat.at_token().is_some()
                    || bind_pat.ref_token().is_some()
                    || bind_pat.mut_token().is_some()
                {
                    self.is_pat_binding_or_const = false;
                }
                if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() {
                    self.is_pat_binding_or_const = false;
                }
                if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) {
                    if let Some(pat) = let_stmt.pat() {
                        if bind_pat.syntax().text_range().is_subrange(&pat.syntax().text_range()) {
                            self.is_pat_binding_or_const = false;
                        }
                    }
                }
            }
            if is_node::<ast::Param>(name.syntax()) {
                self.is_param = true;
                return;
            }
            // FIXME: remove this (^) duplication and make the check more precise
            if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
                self.record_pat_syntax =
                    self.sema.find_node_at_offset_with_macros(&original_file, offset);
            }
        }
    }

    fn classify_name_ref(
        &mut self,
        original_file: &SyntaxNode,
        name_ref: ast::NameRef,
        offset: TextUnit,
    ) {
        self.name_ref_syntax =
            find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
        let name_range = name_ref.syntax().text_range();
        if ast::RecordField::for_field_name(&name_ref).is_some() {
            self.record_lit_syntax =
                self.sema.find_node_at_offset_with_macros(&original_file, offset);
        }

        self.impl_def = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
            .find_map(ast::ImplDef::cast);

        let top_node = name_ref
            .syntax()
            .ancestors()
            .take_while(|it| it.text_range() == name_range)
            .last()
            .unwrap();

        match top_node.parent().map(|it| it.kind()) {
            Some(SOURCE_FILE) | Some(ITEM_LIST) => {
                self.is_new_item = true;
                return;
            }
            _ => (),
        }

        self.use_item_syntax =
            self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);

        self.call_info = call_info(self.db, self.file_position);

        self.function_syntax = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
            .find_map(ast::FnDef::cast);

        self.record_field_syntax = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| {
                it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
            })
            .find_map(ast::RecordField::cast);

        let parent = match name_ref.syntax().parent() {
            Some(it) => it,
            None => return,
        };

        if let Some(segment) = ast::PathSegment::cast(parent.clone()) {
            let path = segment.parent_path();
            self.is_call = path
                .syntax()
                .parent()
                .and_then(ast::PathExpr::cast)
                .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
                .is_some();
            self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();

            self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
            self.has_type_args = segment.type_arg_list().is_some();

            if let Some(path) = hir::Path::from_ast(path.clone()) {
                if let Some(path_prefix) = path.qualifier() {
                    self.path_prefix = Some(path_prefix);
                    return;
                }
            }

            if path.qualifier().is_none() {
                self.is_trivial_path = true;

                // Find either enclosing expr statement (thing with `;`) or a
                // block. If block, check that we are the last expr.
                self.can_be_stmt = name_ref
                    .syntax()
                    .ancestors()
                    .find_map(|node| {
                        if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
                            return Some(
                                stmt.syntax().text_range() == name_ref.syntax().text_range(),
                            );
                        }
                        if let Some(block) = ast::Block::cast(node) {
                            return Some(
                                block.expr().map(|e| e.syntax().text_range())
                                    == Some(name_ref.syntax().text_range()),
                            );
                        }
                        None
                    })
                    .unwrap_or(false);

                if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
                    if let Some(if_expr) =
                        self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off)
                    {
                        if if_expr.syntax().text_range().end()
                            < name_ref.syntax().text_range().start()
                        {
                            self.after_if = true;
                        }
                    }
                }
            }
        }
        if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
            // The receiver comes before the point of insertion of the fake
            // ident, so it should have the same range in the non-modified file
            self.dot_receiver = field_expr
                .expr()
                .map(|e| e.syntax().text_range())
                .and_then(|r| find_node_with_range(original_file, r));
            self.dot_receiver_is_ambiguous_float_literal =
                if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
                    match l.kind() {
                        ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
                        _ => false,
                    }
                } else {
                    false
                }
        }
        if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
            // As above
            self.dot_receiver = method_call_expr
                .expr()
                .map(|e| e.syntax().text_range())
                .and_then(|r| find_node_with_range(original_file, r));
            self.is_call = true;
        }
    }
}

fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
    find_covering_element(syntax, range).ancestors().find_map(N::cast)
}

fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
    match node.ancestors().find_map(N::cast) {
        None => false,
        Some(n) => n.syntax().text_range() == node.text_range(),
    }
}
<commit_msg>feat: improve dot completions with scoring<commit_after>//! FIXME: write short doc here

use hir::{Semantics, SemanticsScope};
use ra_db::SourceDatabase;
use ra_ide_db::RootDatabase;
use ra_syntax::{
    algo::{find_covering_element, find_node_at_offset},
    ast, AstNode,
    SyntaxKind::*,
    SyntaxNode, SyntaxToken, TextRange, TextUnit,
};
use ra_text_edit::AtomTextEdit;

use crate::{completion::CompletionConfig, FilePosition};

/// `CompletionContext` is created early during completion to figure out, where
/// exactly is the cursor, syntax-wise.
#[derive(Debug)]
pub(crate) struct CompletionContext<'a> {
    pub(super) sema: Semantics<'a, RootDatabase>,
    pub(super) db: &'a RootDatabase,
    pub(super) config: &'a CompletionConfig,
    pub(super) offset: TextUnit,
    pub(super) file_position: FilePosition,
    /// The token before the cursor, in the original file.
    pub(super) original_token: SyntaxToken,
    /// The token before the cursor, in the macro-expanded file.
    pub(super) token: SyntaxToken,
    pub(super) krate: Option<hir::Crate>,
    pub(super) name_ref_syntax: Option<ast::NameRef>,
    pub(super) function_syntax: Option<ast::FnDef>,
    pub(super) use_item_syntax: Option<ast::UseItem>,
    pub(super) record_lit_syntax: Option<ast::RecordLit>,
    pub(super) record_pat_syntax: Option<ast::RecordPat>,
    pub(super) record_field_syntax: Option<ast::RecordField>,
    pub(super) impl_def: Option<ast::ImplDef>,
    pub(super) is_param: bool,
    /// If a name-binding or reference to a const in a pattern.
    /// Irrefutable patterns (like let) are excluded.
    pub(super) is_pat_binding_or_const: bool,
    /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
    pub(super) is_trivial_path: bool,
    /// If not a trivial path, the prefix (qualifier).
    pub(super) path_prefix: Option<hir::Path>,
    pub(super) after_if: bool,
    /// `true` if we are a statement or a last expr in the block.
    pub(super) can_be_stmt: bool,
    /// Something is typed at the "top" level, in module or impl/trait.
    pub(super) is_new_item: bool,
    /// The receiver if this is a field or method access, i.e. writing something.<|>
    pub(super) dot_receiver: Option<ast::Expr>,
    pub(super) dot_receiver_is_ambiguous_float_literal: bool,
    /// If this is a call (method or function) in particular, i.e. the () are already there.
    pub(super) is_call: bool,
    /// If this is a macro call, i.e. the () are already there.
    pub(super) is_macro_call: bool,
    pub(super) is_path_type: bool,
    pub(super) has_type_args: bool,
}

impl<'a> CompletionContext<'a> {
    pub(super) fn new(
        db: &'a RootDatabase,
        position: FilePosition,
        config: &'a CompletionConfig,
    ) -> Option<CompletionContext<'a>> {
        let sema = Semantics::new(db);

        let original_file = sema.parse(position.file_id);

        // Insert a fake ident to get a valid parse tree. We will use this file
        // to determine context, though the original_file will be used for
        // actual completion.
        let file_with_fake_ident = {
            let parse = db.parse(position.file_id);
            let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string());
            parse.reparse(&edit).tree()
        };
        let fake_ident_token =
            file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap();

        let krate = sema.to_module_def(position.file_id).map(|m| m.krate());
        let original_token =
            original_file.syntax().token_at_offset(position.offset).left_biased()?;
        let token = sema.descend_into_macros(original_token.clone());
        let mut ctx = CompletionContext {
            sema,
            db,
            config,
            original_token,
            token,
            offset: position.offset,
            file_position: position,
            krate,
            name_ref_syntax: None,
            function_syntax: None,
            use_item_syntax: None,
            record_lit_syntax: None,
            record_pat_syntax: None,
            record_field_syntax: None,
            impl_def: None,
            is_param: false,
            is_pat_binding_or_const: false,
            is_trivial_path: false,
            path_prefix: None,
            after_if: false,
            can_be_stmt: false,
            is_new_item: false,
            dot_receiver: None,
            is_call: false,
            is_macro_call: false,
            is_path_type: false,
            has_type_args: false,
            dot_receiver_is_ambiguous_float_literal: false,
        };

        let mut original_file = original_file.syntax().clone();
        let mut hypothetical_file = file_with_fake_ident.syntax().clone();
        let mut offset = position.offset;
        let mut fake_ident_token = fake_ident_token;

        // Are we inside a macro call?
        while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
            find_node_at_offset::<ast::MacroCall>(&original_file, offset),
            find_node_at_offset::<ast::MacroCall>(&hypothetical_file, offset),
        ) {
            if actual_macro_call.path().as_ref().map(|s| s.syntax().text())
                != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text())
            {
                break;
            }
            let hypothetical_args = match macro_call_with_fake_ident.token_tree() {
                Some(tt) => tt,
                None => break,
            };
            if let (Some(actual_expansion), Some(hypothetical_expansion)) = (
                ctx.sema.expand(&actual_macro_call),
                ctx.sema.expand_hypothetical(
                    &actual_macro_call,
                    &hypothetical_args,
                    fake_ident_token,
                ),
            ) {
                let new_offset = hypothetical_expansion.1.text_range().start();
                if new_offset > actual_expansion.text_range().end() {
                    break;
                }
                original_file = actual_expansion;
                hypothetical_file = hypothetical_expansion.0;
                fake_ident_token = hypothetical_expansion.1;
                offset = new_offset;
            } else {
                break;
            }
        }

        ctx.fill(&original_file, hypothetical_file, offset);
        Some(ctx)
    }

    // The range of the identifier that is being completed.
    pub(crate) fn source_range(&self) -> TextRange {
        // check kind of macro-expanded token, but use range of original token
        match self.token.kind() {
            // workaroud when completion is triggered by trigger characters.
            IDENT => self.original_token.text_range(),
            _ => TextRange::offset_len(self.offset, 0.into()),
        }
    }

    pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> {
        self.sema.scope_at_offset(&self.token.parent(), self.offset)
    }

    fn fill(
        &mut self,
        original_file: &SyntaxNode,
        file_with_fake_ident: SyntaxNode,
        offset: TextUnit,
    ) {
        // First, let's try to complete a reference to some declaration.
        if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
            // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
            // See RFC#1685.
            if is_node::<ast::Param>(name_ref.syntax()) {
                self.is_param = true;
                return;
            }
            // FIXME: remove this (V) duplication and make the check more precise
            if name_ref.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
                self.record_pat_syntax =
                    self.sema.find_node_at_offset_with_macros(&original_file, offset);
            }
            self.classify_name_ref(original_file, name_ref, offset);
        }

        // Otherwise, see if this is a declaration. We can use heuristics to
        // suggest declaration names, see `CompletionKind::Magic`.
        if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
            if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
                self.is_pat_binding_or_const = true;
                if bind_pat.at_token().is_some()
                    || bind_pat.ref_token().is_some()
                    || bind_pat.mut_token().is_some()
                {
                    self.is_pat_binding_or_const = false;
                }
                if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() {
                    self.is_pat_binding_or_const = false;
                }
                if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) {
                    if let Some(pat) = let_stmt.pat() {
                        if bind_pat.syntax().text_range().is_subrange(&pat.syntax().text_range()) {
                            self.is_pat_binding_or_const = false;
                        }
                    }
                }
            }
            if is_node::<ast::Param>(name.syntax()) {
                self.is_param = true;
                return;
            }
            // FIXME: remove this (^) duplication and make the check more precise
            if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
                self.record_pat_syntax =
                    self.sema.find_node_at_offset_with_macros(&original_file, offset);
            }
        }
    }

    fn classify_name_ref(
        &mut self,
        original_file: &SyntaxNode,
        name_ref: ast::NameRef,
        offset: TextUnit,
    ) {
        self.name_ref_syntax =
            find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
        let name_range = name_ref.syntax().text_range();
        if ast::RecordField::for_field_name(&name_ref).is_some() {
            self.record_lit_syntax =
                self.sema.find_node_at_offset_with_macros(&original_file, offset);
        }

        self.impl_def = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
            .find_map(ast::ImplDef::cast);

        let top_node = name_ref
            .syntax()
            .ancestors()
            .take_while(|it| it.text_range() == name_range)
            .last()
            .unwrap();

        match top_node.parent().map(|it| it.kind()) {
            Some(SOURCE_FILE) | Some(ITEM_LIST) => {
                self.is_new_item = true;
                return;
            }
            _ => (),
        }

        self.use_item_syntax =
            self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);

        self.function_syntax = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
            .find_map(ast::FnDef::cast);

        self.record_field_syntax = self
            .sema
            .ancestors_with_macros(self.token.parent())
            .take_while(|it| {
                it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
            })
            .find_map(ast::RecordField::cast);

        let parent = match name_ref.syntax().parent() {
            Some(it) => it,
            None => return,
        };

        if let Some(segment) = ast::PathSegment::cast(parent.clone()) {
            let path = segment.parent_path();
            self.is_call = path
                .syntax()
                .parent()
                .and_then(ast::PathExpr::cast)
                .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
                .is_some();
            self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();

            self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
            self.has_type_args = segment.type_arg_list().is_some();

            if let Some(path) = hir::Path::from_ast(path.clone()) {
                if let Some(path_prefix) = path.qualifier() {
                    self.path_prefix = Some(path_prefix);
                    return;
                }
            }

            if path.qualifier().is_none() {
                self.is_trivial_path = true;

                // Find either enclosing expr statement (thing with `;`) or a
                // block. If block, check that we are the last expr.
                self.can_be_stmt = name_ref
                    .syntax()
                    .ancestors()
                    .find_map(|node| {
                        if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
                            return Some(
                                stmt.syntax().text_range() == name_ref.syntax().text_range(),
                            );
                        }
                        if let Some(block) = ast::Block::cast(node) {
                            return Some(
                                block.expr().map(|e| e.syntax().text_range())
                                    == Some(name_ref.syntax().text_range()),
                            );
                        }
                        None
                    })
                    .unwrap_or(false);

                if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
                    if let Some(if_expr) =
                        self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off)
                    {
                        if if_expr.syntax().text_range().end()
                            < name_ref.syntax().text_range().start()
                        {
                            self.after_if = true;
                        }
                    }
                }
            }
        }
        if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
            // The receiver comes before the point of insertion of the fake
            // ident, so it should have the same range in the non-modified file
            self.dot_receiver = field_expr
                .expr()
                .map(|e| e.syntax().text_range())
                .and_then(|r| find_node_with_range(original_file, r));
            self.dot_receiver_is_ambiguous_float_literal =
                if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
                    match l.kind() {
                        ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
                        _ => false,
                    }
                } else {
                    false
                }
        }
        if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
            // As above
            self.dot_receiver = method_call_expr
                .expr()
                .map(|e| e.syntax().text_range())
                .and_then(|r| find_node_with_range(original_file, r));
            self.is_call = true;
        }
    }
}

fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
    find_covering_element(syntax, range).ancestors().find_map(N::cast)
}

fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
    match node.ancestors().find_map(N::cast) {
        None => false,
        Some(n) => n.syntax().text_range() == node.text_range(),
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use super::x86asm::outb;
use super::x86asm::inb;
use core::prelude::Str;

const COM1 : u16 = 0x3f8;
static mut uartInitialized : bool = false;

pub fn early_init () {
	uart_putc("hello");
	outb(COM1+2 , 0);
	outb(COM1+3, 0x80);    // Unlock divisor
	outb(COM1+0, 12);
	outb(COM1+1, 0);
	outb(COM1+3, 0x03);    // Lock divisor, 8 data bits.
	outb(COM1+4, 0);
	outb(COM1+1, 0x01);    // Enable receive interrupts.

	if inb(COM1+5) == 0xff {
		return;
	}

	unsafe {
		uartInitialized = true;
	}

	outb(COM1, 65);
}

fn uart_putc(text: &str) {
}
<commit_msg>figured out how to use str.bytes...almost<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use super::x86asm::outb;
use super::x86asm::inb;

use core::str::StrPrelude;

const COM1 : u16 = 0x3f8;
static mut uartInitialized : bool = false;

pub fn early_init () {
	outb(COM1+2 , 0);
	outb(COM1+3, 0x80);    // Unlock divisor
	outb(COM1+0, 12);
	outb(COM1+1, 0);
	outb(COM1+3, 0x03);    // Lock divisor, 8 data bits.
	outb(COM1+4, 0);
	outb(COM1+1, 0x01);    // Enable receive interrupts.

	if inb(COM1+5) == 0xff {
		return;
	}

	unsafe {
		uartInitialized = true;
	}

	outb(COM1, 65);
	uart_putc("123456");
}

fn uart_putc(text: &str) {
	for b in text.bytes() {
		outb(COM1, 67);
	}
}
<|endoftext|>


<commit_before>/// DrawObjectList interns shaders, brushes, and scripts, returning references that can be stored
/// in the event queue.
/// TODO: scripts
/// TODO: serialization
/// TODO: further backing store, caching init objs by sha1 or so
/// TODO: free shaders + textures on gl pause
/// TODO: cleanup, deduplication
///
/// more importantly, switch to a map and return keys, rather than using indices

use core::prelude::*;
use core::mem;
use core::fmt::Show;
use collections::vec::Vec;
use std::hash::Hash;
use std::hash::sip::SipHasher;

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use copyshader::CopyShader;
use gltexture::{PixelFormat, Texture, BrushTexture};
use pointshader::PointShader;
use glcommon::Shader;
use luascript::LuaScript;
use arena::TypedArena;
use glcommon::GLResult;
use glcommon::{FillDefaults, MString};

use core::borrow::IntoCow;

/// Holds GL objects that can be inited using the given keys.
/// The list is to avoid having to pass those keys around, and serialize more easily.
/// The arena doesn't relocate its entries, so we can pass back longer-lived pointers,
/// even if it needs some encouragement to do so.
/// There ought to be a better way.
pub struct DrawObjectList<'a, T: 'a, Init: Eq+Hash<SipHasher>+'a> {
    map: HashMap<&'a Init, DrawObjectIndex<T>, SipHasher>,
    list: Vec<&'a T>,
    arena: TypedArena<T>,
}

// copy doesn't work, wtf
#[deriving(Show, Copy)]
pub struct DrawObjectIndex<T>(i32);

impl<T> DrawObjectIndex<T> {
    pub fn error() -> DrawObjectIndex<T> {
        unsafe { mem::transmute(-1i32) }
    }
}

// again, wtf, why is this needed
impl<T> Clone for DrawObjectIndex<T> {
    fn clone(&self) -> DrawObjectIndex<T> {
        let DrawObjectIndex(idx) = *self;
        DrawObjectIndex(idx)
    }
}

pub type ShaderInitValues = (MString, MString);
pub type BrushInitValues = (PixelFormat, (i32, i32), Vec<u8>);
pub type LuaInitValues = MString;
//pub type ShaderKeyValues = &(String, String);
//pub type BrushKeyValues = (PixelFormat, (i32, i32), Vec<u8>>);
//pub type LuaKeyValues = &String;
pub type ShaderUnfilledValues = (Option<MString>, Option<MString>);
pub type BrushUnfilledValues = BrushInitValues;
pub type LuaUnfilledValues = Option<MString>;
pub type PointShaderIndex = DrawObjectIndex<PointShader>;
pub type CopyShaderIndex = DrawObjectIndex<CopyShader>;
pub type BrushIndex = DrawObjectIndex<Texture>;
pub type LuaIndex = DrawObjectIndex<LuaScript>;

pub trait InitFromCache<Init> {
    fn init(Init) -> Self;
}
pub trait MaybeInitFromCache<Init> {
    fn maybe_init(Init) -> GLResult<Self>;
    fn get_source(&self) -> &Init;
}

// this and the two shader impls were originally a single
// impl<T: Shader> InitFromCache<ShaderInitValues> for Option<T>
// but that counts as the impl for all of Option, not just Option<Shader>
fn _init_copy_shader<T: Shader>(value: (MString, MString)) -> GLResult<T> {
    let (vert, frag) = value;
    Shader::new(vert, frag)
}
impl MaybeInitFromCache<ShaderInitValues> for CopyShader {
    fn maybe_init(value: (MString, MString)) -> GLResult<CopyShader> { _init_copy_shader(value) }
    fn get_source(&self) -> &(MString, MString) { &self.source }
}
impl MaybeInitFromCache<ShaderInitValues> for PointShader {
    fn maybe_init(value: (MString, MString)) -> GLResult<PointShader> { _init_copy_shader(value) }
    fn get_source(&self) -> &(MString, MString) { &self.source }
}
// TODO: use this as the impl for all InitFromCache<Init>
impl MaybeInitFromCache<BrushInitValues> for BrushTexture {
    fn maybe_init(value: BrushInitValues) -> GLResult<BrushTexture> {
        Ok(InitFromCache::init(value))
    }
    fn get_source(&self) -> &BrushInitValues { &self.source }
}

pub fn init_from_defaults<Unfilled, T: MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init>(init: Unfilled) -> GLResult<T> {
    let filled = FillDefaults::fill_defaults(init).val;
    MaybeInitFromCache::<Init>::maybe_init(filled)
}

// FIXME maybe a BrushTexture wrapper?
impl InitFromCache<BrushInitValues> for BrushTexture {
    fn init(value: BrushInitValues) -> BrushTexture {
        let tex = {
            let (ref format, (w, h), ref pixels) = value;
            Texture::with_image(w, h, Some(pixels.as_slice()), *format)
        };
        BrushTexture { texture: tex, source: value }
    }
}

impl MaybeInitFromCache<LuaInitValues> for LuaScript {
    fn maybe_init(value: MString) -> GLResult<LuaScript> {
        LuaScript::new(value)
    }
    fn get_source(&self) -> &MString { &self.source }
}

#[old_impl_check]
impl<'a, Unfilled, T: MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init: Hash<SipHasher>+Eq+Show> DrawObjectList<'a, T, Init> {
    pub fn new() -> DrawObjectList<'a, T, Init> {
        // the default hasher is keyed off of the task-local rng,
        // which would blow up since we don't have a task
        //let mut rng = rand::weak_rng();
        //let hasher = SipHasher::new_with_keys(rng.next_u64(), rng.next_u64());
        // FIXME weak_rng also blows up? can it not find /dev/urandom?
        //let hasher = SipHasher::new_with_keys(0, 0);
        let hasher = ::std::collections::hash_state::DefaultState;
        let map = HashMap::with_hash_state(hasher);
        DrawObjectList {
            map: map,
            list: Vec::new(),
            arena: TypedArena::new(),
        }
    }

    pub fn push_object(&mut self, init: Unfilled) -> GLResult<DrawObjectIndex<T>> {
        // Can't use map.entry() here as it consumes the key
        let filled = FillDefaults::fill_defaults(init).val;
        let filledref: &'a Init = unsafe { mem::transmute(&filled) };
        // see below -- these are safe, we just can't prove it
        match self.map.entry(filledref) {
            Entry::Occupied(entry) => Ok(entry.get().clone()),
            Entry::Vacant(entry) => {
                let inited: T = try!(MaybeInitFromCache::<Init>::maybe_init(filled));
                // ptr's lifetime is limited to &self's, which is fair but not very useful.
                // smart ptrs involve individual allocs but are probably better
                let ptr = self.arena.alloc(inited);
                unsafe {
                    self.list.push(mem::transmute(ptr));
                }
                let index = self.list.len() - 1;
                let objindex = DrawObjectIndex(index as i32);
                entry.insert(objindex.clone());
                Ok(objindex)
            }
        }
    }

    pub fn get_object(&self, i: DrawObjectIndex<T>) -> &'a T {
        let DrawObjectIndex(idx) = i;
        self.list[idx as uint]
    }

    pub fn maybe_get_object(&self, i: DrawObjectIndex<T>) -> GLResult<&'a T> {
        let DrawObjectIndex(idx) = i;
        match self.list.get(idx as uint) {
            Some(x) => Ok(*x),
            None => Err(format!("tried to get glstore index {} of {}", idx, self.list.len()).into_cow()),
        }
    }
}

#[old_impl_check]
impl<'a, Unfilled, T: InitFromCache<Init> + MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init: Hash<SipHasher>+Eq+Show> DrawObjectList<'a, T, Init> {
    pub fn safe_push_object(&mut self, init: Unfilled) -> DrawObjectIndex<T> {
        self.push_object(init).unwrap()
    }
}

#[test]
fn equal_keys_match() {
    let mut list: DrawObjectList<LuaScript, LuaInitValues> = DrawObjectList::new();
    let script_1 = "function main() end".into_cow();
    let script_2 = "function main() end".into_cow();
    let idx_1 = list.push_object(Some(script_1)).unwrap();
    let idx_2 = list.push_object(Some(script_2)).unwrap();
    let (DrawObjectIndex(i1), DrawObjectIndex(i2)) = (idx_1, idx_2);
    assert_eq!(i1, i2);
    println!("test");
}

#[test]
fn different_keys_differ() {
    let mut list: DrawObjectList<LuaScript, LuaInitValues> = DrawObjectList::new();
    let script_1 = "function main() end".into_cow();
    let script_2 = "function main() end \n-- hello world".into_cow();
    let idx_1 = list.push_object(Some(script_1)).unwrap();
    let idx_2 = list.push_object(Some(script_2)).unwrap();
    let (DrawObjectIndex(i1), DrawObjectIndex(i2)) = (idx_1, idx_2);
    assert!(i1 != i2);
    println!("test");
}
<commit_msg>hashes<commit_after>/// DrawObjectList interns shaders, brushes, and scripts, returning references that can be stored
/// in the event queue.
/// TODO: scripts
/// TODO: serialization
/// TODO: further backing store, caching init objs by sha1 or so
/// TODO: free shaders + textures on gl pause
/// TODO: cleanup, deduplication
///
/// more importantly, switch to a map and return keys, rather than using indices

use core::prelude::*;
use core::mem;
use core::fmt::Show;
use collections::vec::Vec;
use std::hash::Hash;

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use copyshader::CopyShader;
use gltexture::{PixelFormat, Texture, BrushTexture};
use pointshader::PointShader;
use glcommon::Shader;
use luascript::LuaScript;
use arena::TypedArena;
use glcommon::GLResult;
use glcommon::{FillDefaults, MString};
use std::collections::hash_map::Hasher;

use core::borrow::IntoCow;

type HashType=::std::collections::hash_map::Hasher;

/// Holds GL objects that can be inited using the given keys.
/// The list is to avoid having to pass those keys around, and serialize more easily.
/// The arena doesn't relocate its entries, so we can pass back longer-lived pointers,
/// even if it needs some encouragement to do so.
/// There ought to be a better way.
pub struct DrawObjectList<'a, T: 'a, Init: Eq+Hash<HashType>+'a> {
    map: HashMap<&'a Init, DrawObjectIndex<T>>,
    list: Vec<&'a T>,
    arena: TypedArena<T>,
}

// copy doesn't work, wtf
#[deriving(Show, Copy)]
pub struct DrawObjectIndex<T>(i32);

impl<T> DrawObjectIndex<T> {
    pub fn error() -> DrawObjectIndex<T> {
        unsafe { mem::transmute(-1i32) }
    }
}

// again, wtf, why is this needed
impl<T> Clone for DrawObjectIndex<T> {
    fn clone(&self) -> DrawObjectIndex<T> {
        let DrawObjectIndex(idx) = *self;
        DrawObjectIndex(idx)
    }
}

pub type ShaderInitValues = (MString, MString);
pub type BrushInitValues = (PixelFormat, (i32, i32), Vec<u8>);
pub type LuaInitValues = MString;
//pub type ShaderKeyValues = &(String, String);
//pub type BrushKeyValues = (PixelFormat, (i32, i32), Vec<u8>>);
//pub type LuaKeyValues = &String;
pub type ShaderUnfilledValues = (Option<MString>, Option<MString>);
pub type BrushUnfilledValues = BrushInitValues;
pub type LuaUnfilledValues = Option<MString>;
pub type PointShaderIndex = DrawObjectIndex<PointShader>;
pub type CopyShaderIndex = DrawObjectIndex<CopyShader>;
pub type BrushIndex = DrawObjectIndex<Texture>;
pub type LuaIndex = DrawObjectIndex<LuaScript>;

pub trait InitFromCache<Init> {
    fn init(Init) -> Self;
}
pub trait MaybeInitFromCache<Init> {
    fn maybe_init(Init) -> GLResult<Self>;
    fn get_source(&self) -> &Init;
}

// this and the two shader impls were originally a single
// impl<T: Shader> InitFromCache<ShaderInitValues> for Option<T>
// but that counts as the impl for all of Option, not just Option<Shader>
fn _init_copy_shader<T: Shader>(value: (MString, MString)) -> GLResult<T> {
    let (vert, frag) = value;
    Shader::new(vert, frag)
}
impl MaybeInitFromCache<ShaderInitValues> for CopyShader {
    fn maybe_init(value: (MString, MString)) -> GLResult<CopyShader> { _init_copy_shader(value) }
    fn get_source(&self) -> &(MString, MString) { &self.source }
}
impl MaybeInitFromCache<ShaderInitValues> for PointShader {
    fn maybe_init(value: (MString, MString)) -> GLResult<PointShader> { _init_copy_shader(value) }
    fn get_source(&self) -> &(MString, MString) { &self.source }
}
// TODO: use this as the impl for all InitFromCache<Init>
impl MaybeInitFromCache<BrushInitValues> for BrushTexture {
    fn maybe_init(value: BrushInitValues) -> GLResult<BrushTexture> {
        Ok(InitFromCache::init(value))
    }
    fn get_source(&self) -> &BrushInitValues { &self.source }
}

pub fn init_from_defaults<Unfilled, T: MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init>(init: Unfilled) -> GLResult<T> {
    let filled = FillDefaults::fill_defaults(init).val;
    MaybeInitFromCache::<Init>::maybe_init(filled)
}

// FIXME maybe a BrushTexture wrapper?
impl InitFromCache<BrushInitValues> for BrushTexture {
    fn init(value: BrushInitValues) -> BrushTexture {
        let tex = {
            let (ref format, (w, h), ref pixels) = value;
            Texture::with_image(w, h, Some(pixels.as_slice()), *format)
        };
        BrushTexture { texture: tex, source: value }
    }
}

impl MaybeInitFromCache<LuaInitValues> for LuaScript {
    fn maybe_init(value: MString) -> GLResult<LuaScript> {
        LuaScript::new(value)
    }
    fn get_source(&self) -> &MString { &self.source }
}

#[old_impl_check]
impl<'a, Unfilled, T: MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init: Hash<HashType>+Eq+Show> DrawObjectList<'a, T, Init> {
    pub fn new() -> DrawObjectList<'a, T, Init> {
        // the default hasher is keyed off of the task-local rng,
        // which would blow up since we don't have a task
        //let mut rng = rand::weak_rng();
        //let hasher = SipHasher::new_with_keys(rng.next_u64(), rng.next_u64());
        // FIXME weak_rng also blows up? can it not find /dev/urandom?
        //let hasher = SipHasher::new_with_keys(0, 0);
        let hasher = ::std::collections::hash_state::DefaultState;
        let map = HashMap::with_hash_state(hasher);
        DrawObjectList {
            map: map,
            list: Vec::new(),
            arena: TypedArena::new(),
        }
    }

    pub fn push_object(&mut self, init: Unfilled) -> GLResult<DrawObjectIndex<T>> {
        // Can't use map.entry() here as it consumes the key
        let filled = FillDefaults::fill_defaults(init).val;
        let filledref: &'a Init = unsafe { mem::transmute(&filled) };
        // see below -- these are safe, we just can't prove it
        match self.map.entry(filledref) {
            Entry::Occupied(entry) => Ok(entry.get().clone()),
            Entry::Vacant(entry) => {
                let inited: T = try!(MaybeInitFromCache::<Init>::maybe_init(filled));
                // ptr's lifetime is limited to &self's, which is fair but not very useful.
                // smart ptrs involve individual allocs but are probably better
                let ptr = self.arena.alloc(inited);
                unsafe {
                    self.list.push(mem::transmute(ptr));
                }
                let index = self.list.len() - 1;
                let objindex = DrawObjectIndex(index as i32);
                entry.insert(objindex.clone());
                Ok(objindex)
            }
        }
    }

    pub fn get_object(&self, i: DrawObjectIndex<T>) -> &'a T {
        let DrawObjectIndex(idx) = i;
        self.list[idx as uint]
    }

    pub fn maybe_get_object(&self, i: DrawObjectIndex<T>) -> GLResult<&'a T> {
        let DrawObjectIndex(idx) = i;
        match self.list.get(idx as uint) {
            Some(x) => Ok(*x),
            None => Err(format!("tried to get glstore index {} of {}", idx, self.list.len()).into_cow()),
        }
    }
}

#[old_impl_check]
impl<'a, Unfilled, T: InitFromCache<Init> + MaybeInitFromCache<Init> + FillDefaults<Unfilled, Init, T>, Init: Hash<HashType>+Eq+Show> DrawObjectList<'a, T, Init> {
    pub fn safe_push_object(&mut self, init: Unfilled) -> DrawObjectIndex<T> {
        self.push_object(init).unwrap()
    }
}

#[test]
fn equal_keys_match() {
    let mut list: DrawObjectList<LuaScript, LuaInitValues> = DrawObjectList::new();
    let script_1 = "function main() end".into_cow();
    let script_2 = "function main() end".into_cow();
    let idx_1 = list.push_object(Some(script_1)).unwrap();
    let idx_2 = list.push_object(Some(script_2)).unwrap();
    let (DrawObjectIndex(i1), DrawObjectIndex(i2)) = (idx_1, idx_2);
    assert_eq!(i1, i2);
    println!("test");
}

#[test]
fn different_keys_differ() {
    let mut list: DrawObjectList<LuaScript, LuaInitValues> = DrawObjectList::new();
    let script_1 = "function main() end".into_cow();
    let script_2 = "function main() end \n-- hello world".into_cow();
    let idx_1 = list.push_object(Some(script_1)).unwrap();
    let idx_2 = list.push_object(Some(script_2)).unwrap();
    let (DrawObjectIndex(i1), DrawObjectIndex(i2)) = (idx_1, idx_2);
    assert!(i1 != i2);
    println!("test");
}
<|endoftext|>


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

//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use crate::syntax::{ast, source_map};
use lazy_static::lazy_static;
use std::default::Default;
use std::io::Read;
use std::sync::Mutex;
use std::{env, fmt, fs, io, path};
use toml;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[source_map::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => {
                    if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    }
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            use serde_derive::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all="kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            crate::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(crate::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN", "NaNs",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold", 16384 => u64),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
}

impl Default for Conf {
    fn default() -> Self {
        toml::from_str("").expect("we never error on empty config files")
    }
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != io::ErrorKind::NotFound {
                        return Err(e);
                    }
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (Conf::default(), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS.lock().expect("no threading -> mutex always safe").split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<commit_msg>typo: emum → enum<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use crate::syntax::{ast, source_map};
use lazy_static::lazy_static;
use std::default::Default;
use std::io::Read;
use std::sync::Mutex;
use std::{env, fmt, fs, io, path};
use toml;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[source_map::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => {
                    if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    }
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            use serde_derive::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all="kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            crate::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(crate::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN", "NaNs",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold", 16384 => u64),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
}

impl Default for Conf {
    fn default() -> Self {
        toml::from_str("").expect("we never error on empty config files")
    }
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != io::ErrorKind::NotFound {
                        return Err(e);
                    }
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (Conf::default(), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS.lock().expect("no threading -> mutex always safe").split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<|endoftext|>


<commit_before>// Manages a single participant in the epoch scheme. This is where all
// of the actual epoch management logic happens!

use std::cell::Cell;
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};

use mem::epoch::{Atomic, Guard, global};
use mem::epoch::participants::ParticipantNode;

/// Thread-local data for epoch participation.
pub struct Participant {
    /// The local epoch.
    epoch: AtomicUsize,

    /// Number of pending uses of `epoch::pin()`; keeping a count allows for
    /// reentrant use of epoch management.
    in_critical: AtomicUsize,

    /// Number of operations since last GC
    num_ops: Cell<u64>,

    /// Is the thread still active? Becomes `false` when the thread exits. This
    /// is ultimately used to free `Participant` records.
    pub active: AtomicBool,

    /// The participant list is coded intrusively; here's the `next` pointer.
    pub next: Atomic<ParticipantNode>,
}

unsafe impl Sync for Participant {}

const GC_THRESH: u64 = 128;

impl Participant {
    pub fn new() -> Participant {
        Participant {
            epoch: AtomicUsize::new(0),
            in_critical: AtomicUsize::new(0),
            num_ops: Cell::new(0),
            active: AtomicBool::new(true),
            next: Atomic::null(),
        }
    }

    /// Enter a critical section.
    ///
    /// This method is reentrant, allowing for nested critical sections.
    ///
    /// Returns `true` is this is the first entry on the stack (as opposed to a
    /// re-entrant call).
    pub fn enter(&self) -> bool {
        let new_count = self.in_critical.load(Relaxed) + 1;
        self.in_critical.store(new_count, Relaxed);
        if new_count > 1 { return false }

        atomic::fence(SeqCst);

        let global_epoch = global::get().epoch.load(Relaxed);
        if global_epoch != self.epoch.load(Relaxed) {
            self.epoch.store(global_epoch, Relaxed);
            self.num_ops.set(0);
        } else {
            self.num_ops.set(self.num_ops.get() + 1);
        }

        true
    }

    /// Exit the current (nested) critical section.
    pub fn exit(&self) {
        let new_count = self.in_critical.load(Relaxed) - 1;
        self.in_critical.store(
            new_count,
            if new_count > 0 { Relaxed } else { Release });
    }

    /// Begin the reclamation process for a piece of data.
    pub unsafe fn reclaim<T>(&self, data: *mut T) {
        let cur_global = global::get().epoch.load(Acquire);
        global::get().garbage[cur_global % 3].insert(data);
    }

    /// Attempt to collect garbage by moving the global epoch forward.
    ///
    /// Returns `true` on success.
    pub fn try_collect(&self, guard: &Guard) -> bool {
        let cur_epoch = global::get().epoch.load(SeqCst);

        for p in global::get().participants.iter(guard) {
            if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
                return false
            }
        }

        let new_epoch = cur_epoch.wrapping_add(1);
        atomic::fence(Acquire);
        if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
            return false
        }

        self.epoch.store(new_epoch, Relaxed);
        unsafe {
            global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
        }
        self.num_ops.set(0);

        true
    }

    /// Is this participant past its local GC threshhold?
    pub fn should_gc(&self) -> bool {
        self.num_ops.get() >= GC_THRESH
    }
}
<commit_msg>Don't advance the epoch in try_collect until after doing the collection.<commit_after>// Manages a single participant in the epoch scheme. This is where all
// of the actual epoch management logic happens!

use std::cell::Cell;
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};

use mem::epoch::{Atomic, Guard, global};
use mem::epoch::participants::ParticipantNode;

/// Thread-local data for epoch participation.
pub struct Participant {
    /// The local epoch.
    epoch: AtomicUsize,

    /// Number of pending uses of `epoch::pin()`; keeping a count allows for
    /// reentrant use of epoch management.
    in_critical: AtomicUsize,

    /// Number of operations since last GC
    num_ops: Cell<u64>,

    /// Is the thread still active? Becomes `false` when the thread exits. This
    /// is ultimately used to free `Participant` records.
    pub active: AtomicBool,

    /// The participant list is coded intrusively; here's the `next` pointer.
    pub next: Atomic<ParticipantNode>,
}

unsafe impl Sync for Participant {}

const GC_THRESH: u64 = 128;

impl Participant {
    pub fn new() -> Participant {
        Participant {
            epoch: AtomicUsize::new(0),
            in_critical: AtomicUsize::new(0),
            num_ops: Cell::new(0),
            active: AtomicBool::new(true),
            next: Atomic::null(),
        }
    }

    /// Enter a critical section.
    ///
    /// This method is reentrant, allowing for nested critical sections.
    ///
    /// Returns `true` is this is the first entry on the stack (as opposed to a
    /// re-entrant call).
    pub fn enter(&self) -> bool {
        let new_count = self.in_critical.load(Relaxed) + 1;
        self.in_critical.store(new_count, Relaxed);
        if new_count > 1 { return false }

        atomic::fence(SeqCst);

        let global_epoch = global::get().epoch.load(Relaxed);
        if global_epoch != self.epoch.load(Relaxed) {
            self.epoch.store(global_epoch, Relaxed);
            self.num_ops.set(0);
        } else {
            self.num_ops.set(self.num_ops.get() + 1);
        }

        true
    }

    /// Exit the current (nested) critical section.
    pub fn exit(&self) {
        let new_count = self.in_critical.load(Relaxed) - 1;
        self.in_critical.store(
            new_count,
            if new_count > 0 { Relaxed } else { Release });
    }

    /// Begin the reclamation process for a piece of data.
    pub unsafe fn reclaim<T>(&self, data: *mut T) {
        let cur_global = global::get().epoch.load(Acquire);
        global::get().garbage[cur_global % 3].insert(data);
    }

    /// Attempt to collect garbage by moving the global epoch forward.
    ///
    /// Returns `true` on success.
    pub fn try_collect(&self, guard: &Guard) -> bool {
        let cur_epoch = global::get().epoch.load(SeqCst);

        for p in global::get().participants.iter(guard) {
            if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
                return false
            }
        }

        let new_epoch = cur_epoch.wrapping_add(1);
        atomic::fence(Acquire);
        if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
            return false
        }

        unsafe {
            global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
        }
        self.epoch.store(new_epoch, Release);
        self.num_ops.set(0);

        true
    }

    /// Is this participant past its local GC threshhold?
    pub fn should_gc(&self) -> bool {
        self.num_ops.get() >= GC_THRESH
    }
}
<|endoftext|>