<commit_before>//! Completion for cfg

use std::iter;

use ide_db::SymbolKind;
use syntax::SyntaxKind;

use crate::{completions::Completions, context::CompletionContext, CompletionItem};

pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
    let add_completion = |item: &str| {
        let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item);
        completion.insert_text(format!(r#""{}""#, item));
        acc.add(completion.build());
    };

    let previous = iter::successors(ctx.original_token.prev_token(), |t| {
        (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
            .then(|| t.prev_token())
            .flatten()
    })
    .find(|t| matches!(t.kind(), SyntaxKind::IDENT));

    match previous.as_ref().map(|p| p.text()) {
        Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion),
        Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion),
        Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
        Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
        Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
        Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
            let insert_text = format!(r#""{}""#, s);
            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
            item.insert_text(insert_text);

            acc.add(item.build());
        }),
        None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().for_each(|s| {
            let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
            acc.add(item.build());
        }),
    };
}

const KNOWN_ARCH: [&str; 19] = [
    "aarch64",
    "arm",
    "avr",
    "hexagon",
    "mips",
    "mips64",
    "msp430",
    "nvptx64",
    "powerpc",
    "powerpc64",
    "riscv32",
    "riscv64",
    "s390x",
    "sparc",
    "sparc64",
    "wasm32",
    "wasm64",
    "x86",
    "x86_64",
];

const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];

const KNOWN_OS: [&str; 20] = [
    "cuda",
    "dragonfly",
    "emscripten",
    "freebsd",
    "fuchsia",
    "haiku",
    "hermit",
    "illumos",
    "l4re",
    "linux",
    "netbsd",
    "none",
    "openbsd",
    "psp",
    "redox",
    "solaris",
    "uefi",
    "unknown",
    "vxworks",
    "windows",
];

const KNOWN_VENDOR: [&str; 8] =
    ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];
<commit_msg>fix: deduplicate cfg completions<commit_after>//! Completion for cfg

use std::iter;

use ide_db::SymbolKind;
use itertools::Itertools;
use syntax::SyntaxKind;

use crate::{completions::Completions, context::CompletionContext, CompletionItem};

pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
    let add_completion = |item: &str| {
        let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item);
        completion.insert_text(format!(r#""{}""#, item));
        acc.add(completion.build());
    };

    let previous = iter::successors(ctx.original_token.prev_token(), |t| {
        (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
            .then(|| t.prev_token())
            .flatten()
    })
    .find(|t| matches!(t.kind(), SyntaxKind::IDENT));

    match previous.as_ref().map(|p| p.text()) {
        Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion),
        Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion),
        Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
        Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
        Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
        Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
            let insert_text = format!(r#""{}""#, s);
            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
            item.insert_text(insert_text);

            acc.add(item.build());
        }),
        None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
            let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
            acc.add(item.build());
        }),
    };
}

const KNOWN_ARCH: [&str; 19] = [
    "aarch64",
    "arm",
    "avr",
    "hexagon",
    "mips",
    "mips64",
    "msp430",
    "nvptx64",
    "powerpc",
    "powerpc64",
    "riscv32",
    "riscv64",
    "s390x",
    "sparc",
    "sparc64",
    "wasm32",
    "wasm64",
    "x86",
    "x86_64",
];

const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];

const KNOWN_OS: [&str; 20] = [
    "cuda",
    "dragonfly",
    "emscripten",
    "freebsd",
    "fuchsia",
    "haiku",
    "hermit",
    "illumos",
    "l4re",
    "linux",
    "netbsd",
    "none",
    "openbsd",
    "psp",
    "redox",
    "solaris",
    "uefi",
    "unknown",
    "vxworks",
    "windows",
];

const KNOWN_VENDOR: [&str; 8] =
    ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];
<|endoftext|>


<commit_before>use cocoa::base::id;

/// The `MTLResource` protocol defines the interface for any resource
/// object that represents an allocation of GPU memory.
///
/// Your app does not define classes that implement this protocol. Instead,
/// your app allocates buffer objects (`MTLBuffer`) or texture objects (`MTLTexture`)
/// that conform to this protocol.
pub trait MTLResource {
    /// The CPU cache mode used for the CPU mapping of the resource. (read-only).
    ///
    /// # Discussion
    ///
    /// The cache mode is set when you first create a resource and cannot be changed
    /// afterwards.
    ///
    /// Write-combined memory can have surprising performance pitfalls. Consider using
    /// the write-combined cache mode only if writing to normally cached buffers is known
    /// to cause performance issues due to cache pollution. For more information, see the
    /// CPU Cache Modes constants section.
    unsafe fn cpuCacheMode(self) -> MTLCPUCacheMode;

    /// The storage mode used for the CPU mapping of the resource. (read-only).
    ///
    /// # Discussion
    ///
    /// The storage mode is set when you first create a resource and cannot be
    /// changed afterward.
    unsafe fn storageMode(self) -> MTLStorageMode;

    /// The device that created this resource. (read-only).
    ///
    /// # Discussion
    ///
    /// A resource is always associated with the `MTLDevice` that created it and
    /// can be used only with that device.
    unsafe fn device(self) -> id;

    /// A string used to identify this resource.
    unsafe fn label(self) -> id;
    unsafe fn setLabel(self, label: id);

    /// Sets whether a resource can be purged synchronously.
    ///
    /// # Discussion
    ///
    /// If state is `MTLPurgeableStateKeepCurrent`, the current purgeable state is
    /// queried and is not changed.
    ///
    /// If state is `MTLPurgeableStateNonVolatile`, the resource is marked to inform the
    ///caller that the data should not be discarded.
    ///
    /// If state is `MTLPurgeableStateEmpty`, the resource is marked as data that can be
    /// discarded, because the caller no longer needs the contents of the resource.
    ///
    /// If state is `MTLPurgeableStateVolatile`, the resource is marked as data that can
    /// be discarded, even if the caller may need the resource. `MTLResource` objects can
    /// be made purgeable, even if the caller may need the resource, where the implementation
    /// can reclaim the underlying storage at any time without informing the app. Purgeable
    /// resources may enable an app to keep larger caches of idle memory that may be useful
    /// again in the future without the risk of preventing the allocation of more important memory.
    ///
    /// When you use purgeable memory, make sure the block of memory is locked before you access
    /// it. This locking mechanism is necessary to ensure that auto-removal policies do not discard
    /// the data while you are accessing it. Similarly, the locking mechanism ensures that the
    /// virtual memory system has not already discarded the data.
    unsafe fn setPurgeableState(self, state: MTLPurgeableState) -> MTLPurgeableState;
}

impl MTLResource for id {
    unsafe fn cpuCacheMode(self) -> MTLCPUCacheMode {
        msg_send![self, cpuCacheMode]
    }

    unsafe fn storageMode(self) -> MTLStorageMode {
        msg_send![self, storageMode]
    }

    unsafe fn device(self) -> id {
        msg_send![self, device]
    }

    unsafe fn label(self) -> id {
        msg_send![self, label]
    }

    unsafe fn setLabel(self, label: id) {
        msg_send![self, setLabel:label]
    }

    unsafe fn setPurgeableState(self, state: MTLPurgeableState) -> MTLPurgeableState {
        msg_send![self, setPurgeableState:state]
    }
}

/// The CPU cache mode used for the CPU mapping of a resource.
///
/// # Discussion
///
/// Write-combined memory is optimized for resources that the CPU writes into,
/// but never reads. On some implementations, writes may bypass caches, which
/// avoids cache pollution. Read actions may perform very poorly.
///
/// Applications should investigate changing the cache mode only if writing to
/// normally cached buffers is known to cause performance issues due to cache
/// pollution, as write-combined memory can have surprising performance pitfalls.
/// Another approach is to use nontemporal writes to normally cached memory (STNP
/// on ARMv8, _mm_stream_* on x86_64).
#[repr(usize)]
pub enum MTLCPUCacheMode {
    /// The default CPU cache mode.
    MTLCPUCacheModeDefaultCache = 0,

    /// A write-combined CPU cache mode.
    MTLCPUCacheModeWriteCombined = 1
}

/// The storage mode used for the location and mapping of a resource.
///
/// # Discussion
///
/// Changes due to CPU stores outside of the Metal API must be indicated to the
/// application via the `didModifyRange:` method of `MTLBuffer`. In order for
/// the CPU to access up-to-date GPU results, a blit synchronization must be
/// completed via the `synchronizeResource:` or `synchronizeTexture:slice:level:`
/// method of `MTLBlitCommandEncoder`. Blit overhead is incurred only if the GPU
/// has modified the resource.
#[repr(usize)]
pub enum MTLStorageMode {
    /// The default storage mode for buffers.
    MTLStorageModeShared  = 0,

    /// The storage mode for a resource kept entirely in GPU memory.
    MTLStorageModePrivate = 2,
}

// TODO(burtonageo): Placeholder
pub const MTLResourceStorageModeShift: usize = 16;

// TODO(burtonageo): Placeholder
pub const MTLResourceCPUCacheModeShift: usize = 12;

/// Optional arguments used to create and influence behavior of buffer and
/// texture objects.
bitflags! {
    pub flags MTLResourceOptions: usize {
        /// The default CPU cache mode for the resource. Guarantees that read and
        /// write operations are executed in the expected order.
        const MTLResourceCPUCacheModeDefaultCache =
            (::MTLCPUCacheMode::MTLCPUCacheModeDefaultCache as usize) << ::MTLResourceCPUCacheModeShift,

        /// A write-combined CPU cache mode for the resource. Optimized for resources
        /// that the CPU will write into, but never read.
        const MTLResourceCPUCacheModeWriteCombined =
            (::MTLCPUCacheMode::MTLCPUCacheModeWriteCombined as usize) << ::MTLResourceCPUCacheModeShift,

        /// The CPU and GPU both use the same underlying memory when accessing the
        /// contents of the resource. Coherency is guaranteed only at command buffer
        /// boundaries to minimize the required flushing of CPU or GPU caches.
        const MTLResourceStorageModeShared = (::MTLStorageMode::MTLStorageModeShared as usize) <<
                                             ::MTLResourceStorageModeShift,

        /// The storage mode for a resource kept entirely in GPU memory. No coherency
        /// of any kind must be maintained in this mode because the resource will
        /// never be directly accessed by the CPU.
        const MTLResourceStorageModePrivate = (::MTLStorageMode::MTLStorageModePrivate as usize) <<
                                              ::MTLResourceStorageModeShift,

        /// The default CPU cache mode for general-purpose access to the storage
        /// allocation of the resource, which guarantees that read and write operations
        /// are executed in the expected order.
        ///
        /// This constant was deprecated in iOS 9.0 and OS X 10.11. Use
        /// `MTLResourceCPUCacheModeDefaultCache` instead.
        const MTLResourceOptionCPUCacheModeDefault = MTLResourceCPUCacheModeDefaultCache.bits,

        /// A CPU cache mode set to use write-combined memory for the storage allocation
        /// of the resource.
        ///
        /// This constant was deprecated in iOS 9.0 and OS X 10.11. Use
        /// `MTLResourceCPUCacheModeWriteCombined` instead.
        const MTLResourceOptionCPUCacheModeWriteCombined = MTLResourceCPUCacheModeWriteCombined.bits,
    }
}

/// The purgeable state of the resource.
#[repr(usize)]
pub enum MTLPurgeableState {
   MTLPurgeableStateKeepCurrent = 1,
   MTLPurgeableStateNonVolatile = 2,
   MTLPurgeableStateVolatile = 3,
   MTLPurgeableStateEmpty = 4
}
<commit_msg>Add derive(...) attribute to MTLResource enums<commit_after>use cocoa::base::id;

/// The `MTLResource` protocol defines the interface for any resource
/// object that represents an allocation of GPU memory.
///
/// Your app does not define classes that implement this protocol. Instead,
/// your app allocates buffer objects (`MTLBuffer`) or texture objects (`MTLTexture`)
/// that conform to this protocol.
pub trait MTLResource {
    /// The CPU cache mode used for the CPU mapping of the resource. (read-only).
    ///
    /// # Discussion
    ///
    /// The cache mode is set when you first create a resource and cannot be changed
    /// afterwards.
    ///
    /// Write-combined memory can have surprising performance pitfalls. Consider using
    /// the write-combined cache mode only if writing to normally cached buffers is known
    /// to cause performance issues due to cache pollution. For more information, see the
    /// CPU Cache Modes constants section.
    unsafe fn cpuCacheMode(self) -> MTLCPUCacheMode;

    /// The storage mode used for the CPU mapping of the resource. (read-only).
    ///
    /// # Discussion
    ///
    /// The storage mode is set when you first create a resource and cannot be
    /// changed afterward.
    unsafe fn storageMode(self) -> MTLStorageMode;

    /// The device that created this resource. (read-only).
    ///
    /// # Discussion
    ///
    /// A resource is always associated with the `MTLDevice` that created it and
    /// can be used only with that device.
    unsafe fn device(self) -> id;

    /// A string used to identify this resource.
    unsafe fn label(self) -> id;
    unsafe fn setLabel(self, label: id);

    /// Sets whether a resource can be purged synchronously.
    ///
    /// # Discussion
    ///
    /// If state is `MTLPurgeableStateKeepCurrent`, the current purgeable state is
    /// queried and is not changed.
    ///
    /// If state is `MTLPurgeableStateNonVolatile`, the resource is marked to inform the
    ///caller that the data should not be discarded.
    ///
    /// If state is `MTLPurgeableStateEmpty`, the resource is marked as data that can be
    /// discarded, because the caller no longer needs the contents of the resource.
    ///
    /// If state is `MTLPurgeableStateVolatile`, the resource is marked as data that can
    /// be discarded, even if the caller may need the resource. `MTLResource` objects can
    /// be made purgeable, even if the caller may need the resource, where the implementation
    /// can reclaim the underlying storage at any time without informing the app. Purgeable
    /// resources may enable an app to keep larger caches of idle memory that may be useful
    /// again in the future without the risk of preventing the allocation of more important memory.
    ///
    /// When you use purgeable memory, make sure the block of memory is locked before you access
    /// it. This locking mechanism is necessary to ensure that auto-removal policies do not discard
    /// the data while you are accessing it. Similarly, the locking mechanism ensures that the
    /// virtual memory system has not already discarded the data.
    unsafe fn setPurgeableState(self, state: MTLPurgeableState) -> MTLPurgeableState;
}

impl MTLResource for id {
    unsafe fn cpuCacheMode(self) -> MTLCPUCacheMode {
        msg_send![self, cpuCacheMode]
    }

    unsafe fn storageMode(self) -> MTLStorageMode {
        msg_send![self, storageMode]
    }

    unsafe fn device(self) -> id {
        msg_send![self, device]
    }

    unsafe fn label(self) -> id {
        msg_send![self, label]
    }

    unsafe fn setLabel(self, label: id) {
        msg_send![self, setLabel:label]
    }

    unsafe fn setPurgeableState(self, state: MTLPurgeableState) -> MTLPurgeableState {
        msg_send![self, setPurgeableState:state]
    }
}

/// The CPU cache mode used for the CPU mapping of a resource.
///
/// # Discussion
///
/// Write-combined memory is optimized for resources that the CPU writes into,
/// but never reads. On some implementations, writes may bypass caches, which
/// avoids cache pollution. Read actions may perform very poorly.
///
/// Applications should investigate changing the cache mode only if writing to
/// normally cached buffers is known to cause performance issues due to cache
/// pollution, as write-combined memory can have surprising performance pitfalls.
/// Another approach is to use nontemporal writes to normally cached memory (STNP
/// on ARMv8, _mm_stream_* on x86_64).
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(usize)]
pub enum MTLCPUCacheMode {
    /// The default CPU cache mode.
    MTLCPUCacheModeDefaultCache = 0,

    /// A write-combined CPU cache mode.
    MTLCPUCacheModeWriteCombined = 1
}

/// The storage mode used for the location and mapping of a resource.
///
/// # Discussion
///
/// Changes due to CPU stores outside of the Metal API must be indicated to the
/// application via the `didModifyRange:` method of `MTLBuffer`. In order for
/// the CPU to access up-to-date GPU results, a blit synchronization must be
/// completed via the `synchronizeResource:` or `synchronizeTexture:slice:level:`
/// method of `MTLBlitCommandEncoder`. Blit overhead is incurred only if the GPU
/// has modified the resource.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(usize)]
pub enum MTLStorageMode {
    /// The default storage mode for buffers.
    MTLStorageModeShared  = 0,

    /// The storage mode for a resource kept entirely in GPU memory.
    MTLStorageModePrivate = 2,
}

// TODO(burtonageo): Placeholder
pub const MTLResourceStorageModeShift: usize = 16;

// TODO(burtonageo): Placeholder
pub const MTLResourceCPUCacheModeShift: usize = 12;

/// Optional arguments used to create and influence behavior of buffer and
/// texture objects.
bitflags! {
    pub flags MTLResourceOptions: usize {
        /// The default CPU cache mode for the resource. Guarantees that read and
        /// write operations are executed in the expected order.
        const MTLResourceCPUCacheModeDefaultCache =
            (::MTLCPUCacheMode::MTLCPUCacheModeDefaultCache as usize) << ::MTLResourceCPUCacheModeShift,

        /// A write-combined CPU cache mode for the resource. Optimized for resources
        /// that the CPU will write into, but never read.
        const MTLResourceCPUCacheModeWriteCombined =
            (::MTLCPUCacheMode::MTLCPUCacheModeWriteCombined as usize) << ::MTLResourceCPUCacheModeShift,

        /// The CPU and GPU both use the same underlying memory when accessing the
        /// contents of the resource. Coherency is guaranteed only at command buffer
        /// boundaries to minimize the required flushing of CPU or GPU caches.
        const MTLResourceStorageModeShared = (::MTLStorageMode::MTLStorageModeShared as usize) <<
                                             ::MTLResourceStorageModeShift,

        /// The storage mode for a resource kept entirely in GPU memory. No coherency
        /// of any kind must be maintained in this mode because the resource will
        /// never be directly accessed by the CPU.
        const MTLResourceStorageModePrivate = (::MTLStorageMode::MTLStorageModePrivate as usize) <<
                                              ::MTLResourceStorageModeShift,

        /// The default CPU cache mode for general-purpose access to the storage
        /// allocation of the resource, which guarantees that read and write operations
        /// are executed in the expected order.
        ///
        /// This constant was deprecated in iOS 9.0 and OS X 10.11. Use
        /// `MTLResourceCPUCacheModeDefaultCache` instead.
        const MTLResourceOptionCPUCacheModeDefault = MTLResourceCPUCacheModeDefaultCache.bits,

        /// A CPU cache mode set to use write-combined memory for the storage allocation
        /// of the resource.
        ///
        /// This constant was deprecated in iOS 9.0 and OS X 10.11. Use
        /// `MTLResourceCPUCacheModeWriteCombined` instead.
        const MTLResourceOptionCPUCacheModeWriteCombined = MTLResourceCPUCacheModeWriteCombined.bits,
    }
}

/// The purgeable state of the resource.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(usize)]
pub enum MTLPurgeableState {
   MTLPurgeableStateKeepCurrent = 1,
   MTLPurgeableStateNonVolatile = 2,
   MTLPurgeableStateVolatile = 3,
   MTLPurgeableStateEmpty = 4
}
<|endoftext|>


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

use std::sync::Arc;

use ra_db::salsa;

use crate::{
    ids,
    ty::{
        method_resolution::CrateImplBlocks,
        traits::{AssocTyValue, Impl},
        CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
        TypeCtor,
    },
    Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
};

pub use hir_def::db::{
    BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
    DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
    FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
    LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery,
    StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
};
pub use hir_expand::db::{
    AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
    ParseMacroQuery,
};

#[salsa::query_group(HirDatabaseStorage)]
#[salsa::requires(salsa::Database)]
pub trait HirDatabase: DefDatabase + AstDatabase {
    #[salsa::invoke(crate::ty::infer_query)]
    fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::ty::type_for_def)]
    fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;

    #[salsa::invoke(crate::ty::type_for_field)]
    fn type_for_field(&self, field: StructField) -> Ty;

    #[salsa::invoke(crate::ty::callable_item_sig)]
    fn callable_item_signature(&self, def: CallableDef) -> FnSig;

    #[salsa::invoke(crate::ty::generic_predicates_for_param_query)]
    fn generic_predicates_for_param(
        &self,
        def: GenericDef,
        param_idx: u32,
    ) -> Arc<[GenericPredicate]>;

    #[salsa::invoke(crate::ty::generic_predicates_query)]
    fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>;

    #[salsa::invoke(crate::ty::generic_defaults_query)]
    fn generic_defaults(&self, def: GenericDef) -> Substs;

    #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
    fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;

    #[salsa::invoke(crate::ty::traits::impls_for_trait_query)]
    fn impls_for_trait(&self, krate: Crate, trait_: Trait) -> Arc<[ImplBlock]>;

    /// This provides the Chalk trait solver instance. Because Chalk always
    /// works from a specific crate, this query is keyed on the crate; and
    /// because Chalk does its own internal caching, the solver is wrapped in a
    /// Mutex and the query does an untracked read internally, to make sure the
    /// cached state is thrown away when input facts change.
    #[salsa::invoke(crate::ty::traits::trait_solver_query)]
    fn trait_solver(&self, krate: Crate) -> crate::ty::traits::TraitSolver;

    // Interned IDs for Chalk integration
    #[salsa::interned]
    fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
    #[salsa::interned]
    fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId;
    #[salsa::interned]
    fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> ids::AssocTyValueId;

    #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)]
    fn associated_ty_data(
        &self,
        id: chalk_ir::TypeId,
    ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)]
    fn trait_datum(
        &self,
        krate: Crate,
        trait_id: chalk_ir::TraitId,
    ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)]
    fn struct_datum(
        &self,
        krate: Crate,
        struct_id: chalk_ir::StructId,
    ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
    fn impl_datum(
        &self,
        krate: Crate,
        impl_id: chalk_ir::ImplId,
    ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::associated_ty_value_query)]
    fn associated_ty_value(
        &self,
        krate: Crate,
        id: chalk_rust_ir::AssociatedTyValueId,
    ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::trait_solve_query)]
    fn trait_solve(
        &self,
        krate: Crate,
        goal: crate::ty::Canonical<crate::ty::InEnvironment<crate::ty::Obligation>>,
    ) -> Option<crate::ty::traits::Solution>;
}

#[test]
fn hir_database_is_object_safe() {
    fn _assert_object_safe(_: &dyn HirDatabase) {}
}
<commit_msg>Remove unneded supertrait<commit_after>//! FIXME: write short doc here

use std::sync::Arc;

use ra_db::salsa;

use crate::{
    ids,
    ty::{
        method_resolution::CrateImplBlocks,
        traits::{AssocTyValue, Impl},
        CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
        TypeCtor,
    },
    Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
};

pub use hir_def::db::{
    BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
    DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
    FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
    LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery,
    StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
};
pub use hir_expand::db::{
    AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
    ParseMacroQuery,
};

#[salsa::query_group(HirDatabaseStorage)]
#[salsa::requires(salsa::Database)]
pub trait HirDatabase: DefDatabase {
    #[salsa::invoke(crate::ty::infer_query)]
    fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::ty::type_for_def)]
    fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;

    #[salsa::invoke(crate::ty::type_for_field)]
    fn type_for_field(&self, field: StructField) -> Ty;

    #[salsa::invoke(crate::ty::callable_item_sig)]
    fn callable_item_signature(&self, def: CallableDef) -> FnSig;

    #[salsa::invoke(crate::ty::generic_predicates_for_param_query)]
    fn generic_predicates_for_param(
        &self,
        def: GenericDef,
        param_idx: u32,
    ) -> Arc<[GenericPredicate]>;

    #[salsa::invoke(crate::ty::generic_predicates_query)]
    fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>;

    #[salsa::invoke(crate::ty::generic_defaults_query)]
    fn generic_defaults(&self, def: GenericDef) -> Substs;

    #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
    fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;

    #[salsa::invoke(crate::ty::traits::impls_for_trait_query)]
    fn impls_for_trait(&self, krate: Crate, trait_: Trait) -> Arc<[ImplBlock]>;

    /// This provides the Chalk trait solver instance. Because Chalk always
    /// works from a specific crate, this query is keyed on the crate; and
    /// because Chalk does its own internal caching, the solver is wrapped in a
    /// Mutex and the query does an untracked read internally, to make sure the
    /// cached state is thrown away when input facts change.
    #[salsa::invoke(crate::ty::traits::trait_solver_query)]
    fn trait_solver(&self, krate: Crate) -> crate::ty::traits::TraitSolver;

    // Interned IDs for Chalk integration
    #[salsa::interned]
    fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
    #[salsa::interned]
    fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId;
    #[salsa::interned]
    fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> ids::AssocTyValueId;

    #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)]
    fn associated_ty_data(
        &self,
        id: chalk_ir::TypeId,
    ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)]
    fn trait_datum(
        &self,
        krate: Crate,
        trait_id: chalk_ir::TraitId,
    ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)]
    fn struct_datum(
        &self,
        krate: Crate,
        struct_id: chalk_ir::StructId,
    ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
    fn impl_datum(
        &self,
        krate: Crate,
        impl_id: chalk_ir::ImplId,
    ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::chalk::associated_ty_value_query)]
    fn associated_ty_value(
        &self,
        krate: Crate,
        id: chalk_rust_ir::AssociatedTyValueId,
    ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>;

    #[salsa::invoke(crate::ty::traits::trait_solve_query)]
    fn trait_solve(
        &self,
        krate: Crate,
        goal: crate::ty::Canonical<crate::ty::InEnvironment<crate::ty::Obligation>>,
    ) -> Option<crate::ty::traits::Solution>;
}

#[test]
fn hir_database_is_object_safe() {
    fn _assert_object_safe(_: &dyn HirDatabase) {}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    white_pieces: u32,
    black_pieces: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            white_pieces: 18,
            black_pieces: 18,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
}
<commit_msg>Simplify is_hex_removable<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    white_pieces: u32,
    black_pieces: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            white_pieces: 18,
            black_pieces: 18,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let has_neighbor = |f| self.get_hex_neighbor(coord, f).is_some();
        let is_adjacent = |f| has_neighbor((f + 1) % 6) || has_neighbor((f + 5) % 6);

        let mut neighbor_count = 0;
        for f in 0..6 {
            if has_neighbor(f) {
                if is_adjacent(f) {
                    neighbor_count += 1;
                } else {
                    return false;
                }
            }
        }

        match neighbor_count {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 | 2 | 3 => true,
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
}
<|endoftext|>


<commit_before>
extern crate freetype;

use freetype as ft;
use freetype::ffi;

const WIDTH: ffi::FT_Int = 32;
const HEIGHT: ffi::FT_Int = 24;

fn draw_bitmap(bitmap: &ffi::FT_Bitmap, x: ffi::FT_Int, y: ffi::FT_Int) -> [[u8, ..WIDTH as uint], ..HEIGHT as uint] {
    let mut image: [[u8, ..WIDTH as uint], ..HEIGHT as uint] = [
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
    ];
    let mut p = 0;
    let mut q = 0;
    let x_max = x + bitmap.width;
    let y_max = y + bitmap.rows;

    for i in range(x, x_max) {
        for j in range(y, y_max) {
            if i < 0      || j < 0       ||
               i >= WIDTH || j >= HEIGHT {
                continue;
            }

            unsafe {
                image[j as uint][i as uint] |= *bitmap.buffer.offset((q * bitmap.width + p) as int);
            }
            q += 1;
        }
        q = 0;
        p += 1;
    }

    image
}

fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} font sample-text\n", &args[0]);
        return;
    }

    let ref filename = args[1];
    let ref text = args[2];

    let library = ft::Library::init().unwrap();
    let mut face = library.new_face(filename.as_slice(), 0).unwrap();
    face.set_char_size(40 * 64, 0, 50, 0).unwrap();
    face.load_char(text.nfc_chars().next().unwrap() as u64, ft::face::RENDER).unwrap();

    let slot = face.glyph().raw();
    let image = draw_bitmap(&slot.bitmap, slot.bitmap_left, HEIGHT - slot.bitmap_top);

    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            std::io::print(if image[i as uint][j as uint] == 0 {
                               " "
                           } else if image[i as uint][j as uint] < 128 {
                               "*"
                           } else {
                               "+"
                           });
        }
        std::io::println("");
    }

}
<commit_msg>Use array initializer. Closes #61<commit_after>
extern crate freetype;

use freetype as ft;
use freetype::ffi;

const WIDTH: ffi::FT_Int = 32;
const HEIGHT: ffi::FT_Int = 24;

fn draw_bitmap(bitmap: &ffi::FT_Bitmap, x: ffi::FT_Int, y: ffi::FT_Int) -> [[u8, ..WIDTH as uint], ..HEIGHT as uint] {
    let mut image = [[0u8, ..WIDTH as uint], .. HEIGHT as uint];
    let mut p = 0;
    let mut q = 0;
    let x_max = x + bitmap.width;
    let y_max = y + bitmap.rows;

    for i in range(x, x_max) {
        for j in range(y, y_max) {
            if i < 0      || j < 0       ||
               i >= WIDTH || j >= HEIGHT {
                continue;
            }

            unsafe {
                image[j as uint][i as uint] |= *bitmap.buffer.offset((q * bitmap.width + p) as int);
            }
            q += 1;
        }
        q = 0;
        p += 1;
    }

    image
}

fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} font sample-text\n", &args[0]);
        return;
    }

    let ref filename = args[1];
    let ref text = args[2];

    let library = ft::Library::init().unwrap();
    let mut face = library.new_face(filename.as_slice(), 0).unwrap();
    face.set_char_size(40 * 64, 0, 50, 0).unwrap();
    face.load_char(text.nfc_chars().next().unwrap() as u64, ft::face::RENDER).unwrap();

    let slot = face.glyph().raw();
    let image = draw_bitmap(&slot.bitmap, slot.bitmap_left, HEIGHT - slot.bitmap_top);

    for i in range(0, HEIGHT) {
        for j in range(0, WIDTH) {
            std::io::print(if image[i as uint][j as uint] == 0 {
                               " "
                           } else if image[i as uint][j as uint] < 128 {
                               "*"
                           } else {
                               "+"
                           });
        }
        std::io::println("");
    }

}
<|endoftext|>


<commit_before>use futures::{Async, Future, Poll, task};
use lapin_async::{
  confirmation::Confirmation,
  wait::NotifyReady,
};

use crate::error::Error;

pub struct ConfirmationFuture<T>(Result<Confirmation<T>, Option<Error>>);

struct Watcher(task::Task);

impl NotifyReady for Watcher {
  fn notify(&self) {
    self.0.notify();
  }
}

impl<T> Future for ConfirmationFuture<T> {
  type Item = T;
  type Error = Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    match &mut self.0 {
      Err(err)         => Err(err.take().expect("ConfirmationFuture polled twice but we were in an error state")),
      Ok(confirmation) => match confirmation.try_wait() {
        Some(res) => Ok(Async::Ready(res)),
        None      => {
          confirmation.subscribe(Box::new(Watcher(task::current())));
          Ok(Async::NotReady)
        }
      },
    }
  }
}

impl<T> From<Confirmation<T>> for ConfirmationFuture<T> {
  fn from(confirmation: Confirmation<T>) -> Self {
    Self(confirmation.into_result().map_err(Some))
  }
}
<commit_msg>futures: subscribe early to notifications<commit_after>use futures::{Async, Future, Poll, task};
use lapin_async::{
  confirmation::Confirmation,
  wait::NotifyReady,
};

use crate::error::Error;

pub struct ConfirmationFuture<T> {
  inner:     Result<Confirmation<T>, Option<Error>>,
  subsribed: bool,
}

struct Watcher(task::Task);

impl NotifyReady for Watcher {
  fn notify(&self) {
    self.0.notify();
  }
}

impl<T> Future for ConfirmationFuture<T> {
  type Item = T;
  type Error = Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    match &mut self.inner {
      Err(err)         => Err(err.take().expect("ConfirmationFuture polled twice but we were in an error state")),
      Ok(confirmation) => {
        if !self.subsribed {
          confirmation.subscribe(Box::new(Watcher(task::current())));
          self.subsribed = true;
        }
        Ok(confirmation.try_wait().map(Async::Ready).unwrap_or(Async::NotReady))
      },
    }
  }
}

impl<T> From<Confirmation<T>> for ConfirmationFuture<T> {
  fn from(confirmation: Confirmation<T>) -> Self {
    Self { inner: confirmation.into_result().map_err(Some), subsribed: false }
  }
}
<|endoftext|>


<commit_before>//! Implementation of compiling the compiler and standard library, in "check"-based modes.

use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
use crate::config::TargetSelection;
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
use crate::{Compiler, Mode, Subcommand};
use std::path::PathBuf;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
    pub target: TargetSelection,
}

/// Returns args for the subcommand itself (not for cargo)
fn args(builder: &Builder<'_>) -> Vec<String> {
    fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
        arr.iter().copied().map(String::from)
    }

    if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
        // disable the most spammy clippy lints
        let ignored_lints = vec![
            "many_single_char_names", // there are a lot in stdarch
            "collapsible_if",
            "type_complexity",
            "missing_safety_doc", // almost 3K warnings
            "too_many_arguments",
            "needless_lifetimes", // people want to keep the lifetimes
            "wrong_self_convention",
        ];
        let mut args = vec![];
        if fix {
            #[rustfmt::skip]
            args.extend(strings(&[
                "--fix", "-Zunstable-options",
                // FIXME: currently, `--fix` gives an error while checking tests for libtest,
                // possibly because libtest is not yet built in the sysroot.
                // As a workaround, avoid checking tests and benches when passed --fix.
                "--lib", "--bins", "--examples",
            ]));
        }
        args.extend(strings(&["--", "--cap-lints", "warn"]));
        args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
        args
    } else {
        vec![]
    }
}

fn cargo_subcommand(kind: Kind) -> &'static str {
    match kind {
        Kind::Check => "check",
        Kind::Clippy => "clippy",
        Kind::Fix => "fix",
        _ => unreachable!(),
    }
}

impl Step for Std {
    type Output = ();
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("test")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Std { target: run.target });
    }

    fn run(self, builder: &Builder<'_>) {
        let target = self.target;
        let compiler = builder.compiler(builder.top_stage, builder.config.build);

        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        std_cargo(builder, target, compiler.stage, &mut cargo);

        builder.info(&format!(
            "Checking stage{} std artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_stamp(builder, compiler, target),
            vec![],
            true,
        );

        // We skip populating the sysroot in non-zero stage because that'll lead
        // to rlib/rmeta conflicts if std gets built during this session.
        if compiler.stage == 0 {
            let libdir = builder.sysroot_libdir(compiler, target);
            let hostdir = builder.sysroot_libdir(compiler, compiler.host);
            add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
        }

        // Then run cargo again, once we've put the rmeta files for the library
        // crates into the sysroot. This is needed because e.g., core's tests
        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
        // since we initialize with an empty sysroot.
        //
        // Currently only the "libtest" tree of crates does this.

        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
            let mut cargo = builder.cargo(
                compiler,
                Mode::Std,
                SourceType::InTree,
                target,
                cargo_subcommand(builder.kind),
            );
            std_cargo(builder, target, compiler.stage, &mut cargo);
            cargo.arg("--all-targets");

            // Explicitly pass -p for all dependencies krates -- this will force cargo
            // to also check the tests/benches/examples for these crates, rather
            // than just the leaf crate.
            for krate in builder.in_tree_crates("test", Some(target)) {
                cargo.arg("-p").arg(krate.name);
            }

            builder.info(&format!(
                "Checking stage{} std test/bench/example targets ({} -> {})",
                builder.top_stage, &compiler.host, target
            ));
            run_cargo(
                builder,
                cargo,
                args(builder),
                &libstd_test_stamp(builder, compiler, target),
                vec![],
                true,
            );
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
    pub target: TargetSelection,
}

impl Step for Rustc {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("rustc-main")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Rustc { target: run.target });
    }

    /// Builds the compiler.
    ///
    /// This will build the compiler for a particular stage of the build using
    /// the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;

        if compiler.stage != 0 {
            // If we're not in stage 0, then we won't have a std from the beta
            // compiler around. That means we need to make sure there's one in
            // the sysroot for the compiler to find. Otherwise, we're going to
            // fail when building crates that need to generate code (e.g., build
            // scripts and their dependencies).
            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
            builder.ensure(crate::compile::Std { target, compiler });
        } else {
            builder.ensure(Std { target });
        }

        let mut cargo = builder.cargo(
            compiler,
            Mode::Rustc,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        rustc_cargo(builder, &mut cargo, target);
        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
            cargo.arg("--all-targets");
        }

        // Explicitly pass -p for all compiler krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("rustc-main", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} compiler artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &librustc_stamp(builder, compiler, target),
            vec![],
            true,
        );

        let libdir = builder.sysroot_libdir(compiler, target);
        let hostdir = builder.sysroot_libdir(compiler, compiler.host);
        add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
    pub target: TargetSelection,
    pub backend: Interned<String>,
}

impl Step for CodegenBackend {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
    }

    fn make_run(run: RunConfig<'_>) {
        for &backend in &[INTERNER.intern_str("cranelift")] {
            run.builder.ensure(CodegenBackend { target: run.target, backend });
        }
    }

    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;
        let backend = self.backend;

        builder.ensure(Rustc { target });

        let mut cargo = builder.cargo(
            compiler,
            Mode::Codegen,
            SourceType::Submodule,
            target,
            cargo_subcommand(builder.kind),
        );
        cargo
            .arg("--manifest-path")
            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
        rustc_cargo_env(builder, &mut cargo, target);

        builder.info(&format!(
            "Checking stage{} {} artifacts ({} -> {})",
            builder.top_stage, backend, &compiler.host.triple, target.triple
        ));

        run_cargo(
            builder,
            cargo,
            args(builder),
            &codegen_backend_stamp(builder, compiler, target, backend),
            vec![],
            true,
        );
    }
}

macro_rules! tool_check_step {
    ($name:ident, $path:expr, $source_type:expr) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub target: TargetSelection,
        }

        impl Step for $name {
            type Output = ();
            const ONLY_HOSTS: bool = true;
            const DEFAULT: bool = true;

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                run.path($path)
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name { target: run.target });
            }

            fn run(self, builder: &Builder<'_>) {
                let compiler = builder.compiler(builder.top_stage, builder.config.build);
                let target = self.target;

                builder.ensure(Rustc { target });

                let mut cargo = prepare_tool_cargo(
                    builder,
                    compiler,
                    Mode::ToolRustc,
                    target,
                    cargo_subcommand(builder.kind),
                    $path,
                    $source_type,
                    &[],
                );

                if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
                    cargo.arg("--all-targets");
                }

                // Enable internal lints for clippy and rustdoc
                // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                cargo.rustflag("-Zunstable-options");

                builder.info(&format!(
                    "Checking stage{} {} artifacts ({} -> {})",
                    builder.top_stage,
                    stringify!($name).to_lowercase(),
                    &compiler.host.triple,
                    target.triple
                ));
                run_cargo(
                    builder,
                    cargo,
                    args(builder),
                    &stamp(builder, compiler, target),
                    vec![],
                    true,
                );

                let libdir = builder.sysroot_libdir(compiler, target);
                let hostdir = builder.sysroot_libdir(compiler, compiler.host);
                add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target));

                /// Cargo's output path in a given stage, compiled by a particular
                /// compiler for the specified target.
                fn stamp(
                    builder: &Builder<'_>,
                    compiler: Compiler,
                    target: TargetSelection,
                ) -> PathBuf {
                    builder
                        .cargo_out(compiler, Mode::ToolRustc, target)
                        .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
                }
            }
        }
    };
}

tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
// Clippy is a hybrid. It is an external tool, but uses a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);

tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_test_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}

/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}

/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
    backend: Interned<String>,
) -> PathBuf {
    builder
        .cargo_out(compiler, Mode::Codegen, target)
        .join(format!(".librustc_codegen_{}-check.stamp", backend))
}
<commit_msg>Rollup merge of #84585 - jyn514:check-rustdoc, r=Mark-Simulacrum<commit_after>//! Implementation of compiling the compiler and standard library, in "check"-based modes.

use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
use crate::config::TargetSelection;
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::INTERNER;
use crate::{Compiler, Mode, Subcommand};
use std::path::PathBuf;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
    pub target: TargetSelection,
}

/// Returns args for the subcommand itself (not for cargo)
fn args(builder: &Builder<'_>) -> Vec<String> {
    fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
        arr.iter().copied().map(String::from)
    }

    if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
        // disable the most spammy clippy lints
        let ignored_lints = vec![
            "many_single_char_names", // there are a lot in stdarch
            "collapsible_if",
            "type_complexity",
            "missing_safety_doc", // almost 3K warnings
            "too_many_arguments",
            "needless_lifetimes", // people want to keep the lifetimes
            "wrong_self_convention",
        ];
        let mut args = vec![];
        if fix {
            #[rustfmt::skip]
            args.extend(strings(&[
                "--fix", "-Zunstable-options",
                // FIXME: currently, `--fix` gives an error while checking tests for libtest,
                // possibly because libtest is not yet built in the sysroot.
                // As a workaround, avoid checking tests and benches when passed --fix.
                "--lib", "--bins", "--examples",
            ]));
        }
        args.extend(strings(&["--", "--cap-lints", "warn"]));
        args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
        args
    } else {
        vec![]
    }
}

fn cargo_subcommand(kind: Kind) -> &'static str {
    match kind {
        Kind::Check => "check",
        Kind::Clippy => "clippy",
        Kind::Fix => "fix",
        _ => unreachable!(),
    }
}

impl Step for Std {
    type Output = ();
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("test")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Std { target: run.target });
    }

    fn run(self, builder: &Builder<'_>) {
        let target = self.target;
        let compiler = builder.compiler(builder.top_stage, builder.config.build);

        let mut cargo = builder.cargo(
            compiler,
            Mode::Std,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        std_cargo(builder, target, compiler.stage, &mut cargo);

        builder.info(&format!(
            "Checking stage{} std artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &libstd_stamp(builder, compiler, target),
            vec![],
            true,
        );

        // We skip populating the sysroot in non-zero stage because that'll lead
        // to rlib/rmeta conflicts if std gets built during this session.
        if compiler.stage == 0 {
            let libdir = builder.sysroot_libdir(compiler, target);
            let hostdir = builder.sysroot_libdir(compiler, compiler.host);
            add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
        }

        // Then run cargo again, once we've put the rmeta files for the library
        // crates into the sysroot. This is needed because e.g., core's tests
        // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
        // since we initialize with an empty sysroot.
        //
        // Currently only the "libtest" tree of crates does this.

        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
            let mut cargo = builder.cargo(
                compiler,
                Mode::Std,
                SourceType::InTree,
                target,
                cargo_subcommand(builder.kind),
            );
            std_cargo(builder, target, compiler.stage, &mut cargo);
            cargo.arg("--all-targets");

            // Explicitly pass -p for all dependencies krates -- this will force cargo
            // to also check the tests/benches/examples for these crates, rather
            // than just the leaf crate.
            for krate in builder.in_tree_crates("test", Some(target)) {
                cargo.arg("-p").arg(krate.name);
            }

            builder.info(&format!(
                "Checking stage{} std test/bench/example targets ({} -> {})",
                builder.top_stage, &compiler.host, target
            ));
            run_cargo(
                builder,
                cargo,
                args(builder),
                &libstd_test_stamp(builder, compiler, target),
                vec![],
                true,
            );
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
    pub target: TargetSelection,
}

impl Step for Rustc {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.all_krates("rustc-main")
    }

    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(Rustc { target: run.target });
    }

    /// Builds the compiler.
    ///
    /// This will build the compiler for a particular stage of the build using
    /// the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;

        if compiler.stage != 0 {
            // If we're not in stage 0, then we won't have a std from the beta
            // compiler around. That means we need to make sure there's one in
            // the sysroot for the compiler to find. Otherwise, we're going to
            // fail when building crates that need to generate code (e.g., build
            // scripts and their dependencies).
            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
            builder.ensure(crate::compile::Std { target, compiler });
        } else {
            builder.ensure(Std { target });
        }

        let mut cargo = builder.cargo(
            compiler,
            Mode::Rustc,
            SourceType::InTree,
            target,
            cargo_subcommand(builder.kind),
        );
        rustc_cargo(builder, &mut cargo, target);
        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
            cargo.arg("--all-targets");
        }

        // Explicitly pass -p for all compiler krates -- this will force cargo
        // to also check the tests/benches/examples for these crates, rather
        // than just the leaf crate.
        for krate in builder.in_tree_crates("rustc-main", Some(target)) {
            cargo.arg("-p").arg(krate.name);
        }

        builder.info(&format!(
            "Checking stage{} compiler artifacts ({} -> {})",
            builder.top_stage, &compiler.host, target
        ));
        run_cargo(
            builder,
            cargo,
            args(builder),
            &librustc_stamp(builder, compiler, target),
            vec![],
            true,
        );

        let libdir = builder.sysroot_libdir(compiler, target);
        let hostdir = builder.sysroot_libdir(compiler, compiler.host);
        add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
    pub target: TargetSelection,
    pub backend: Interned<String>,
}

impl Step for CodegenBackend {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
    }

    fn make_run(run: RunConfig<'_>) {
        for &backend in &[INTERNER.intern_str("cranelift")] {
            run.builder.ensure(CodegenBackend { target: run.target, backend });
        }
    }

    fn run(self, builder: &Builder<'_>) {
        let compiler = builder.compiler(builder.top_stage, builder.config.build);
        let target = self.target;
        let backend = self.backend;

        builder.ensure(Rustc { target });

        let mut cargo = builder.cargo(
            compiler,
            Mode::Codegen,
            SourceType::Submodule,
            target,
            cargo_subcommand(builder.kind),
        );
        cargo
            .arg("--manifest-path")
            .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
        rustc_cargo_env(builder, &mut cargo, target);

        builder.info(&format!(
            "Checking stage{} {} artifacts ({} -> {})",
            builder.top_stage, backend, &compiler.host.triple, target.triple
        ));

        run_cargo(
            builder,
            cargo,
            args(builder),
            &codegen_backend_stamp(builder, compiler, target, backend),
            vec![],
            true,
        );
    }
}

macro_rules! tool_check_step {
    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path) => {
        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
        pub struct $name {
            pub target: TargetSelection,
        }

        impl Step for $name {
            type Output = ();
            const ONLY_HOSTS: bool = true;
            const DEFAULT: bool = true;

            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                run.paths(&[ $path, $($alias),* ])
            }

            fn make_run(run: RunConfig<'_>) {
                run.builder.ensure($name { target: run.target });
            }

            fn run(self, builder: &Builder<'_>) {
                let compiler = builder.compiler(builder.top_stage, builder.config.build);
                let target = self.target;

                builder.ensure(Rustc { target });

                let mut cargo = prepare_tool_cargo(
                    builder,
                    compiler,
                    Mode::ToolRustc,
                    target,
                    cargo_subcommand(builder.kind),
                    $path,
                    $source_type,
                    &[],
                );

                if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
                    cargo.arg("--all-targets");
                }

                // Enable internal lints for clippy and rustdoc
                // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                cargo.rustflag("-Zunstable-options");

                builder.info(&format!(
                    "Checking stage{} {} artifacts ({} -> {})",
                    builder.top_stage,
                    stringify!($name).to_lowercase(),
                    &compiler.host.triple,
                    target.triple
                ));
                run_cargo(
                    builder,
                    cargo,
                    args(builder),
                    &stamp(builder, compiler, target),
                    vec![],
                    true,
                );

                let libdir = builder.sysroot_libdir(compiler, target);
                let hostdir = builder.sysroot_libdir(compiler, compiler.host);
                add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target));

                /// Cargo's output path in a given stage, compiled by a particular
                /// compiler for the specified target.
                fn stamp(
                    builder: &Builder<'_>,
                    compiler: Compiler,
                    target: TargetSelection,
                ) -> PathBuf {
                    builder
                        .cargo_out(compiler, Mode::ToolRustc, target)
                        .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
                }
            }
        }
    };
}

tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
// Clippy is a hybrid. It is an external tool, but uses a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);

tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
}

/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
fn libstd_test_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
) -> PathBuf {
    builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
}

/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
    builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}

/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(
    builder: &Builder<'_>,
    compiler: Compiler,
    target: TargetSelection,
    backend: Interned<String>,
) -> PathBuf {
    builder
        .cargo_out(compiler, Mode::Codegen, target)
        .join(format!(".librustc_codegen_{}-check.stamp", backend))
}
<|endoftext|>


<commit_before>use serde::{Serialize, Deserialize};
use toml;

use std::path::Path;
use std::io;
use std::fs;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;

pub struct ConfigFile {}

impl ConfigFile {
    pub fn load<T>(path: &Path) -> Result<T, Box<Error>>
        where T: for<'r> Deserialize<'r>
    {
        let mut file = File::open(path)?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        toml::de::from_str(&toml).map_err(|_| {
            let e = io::Error::new(io::ErrorKind::InvalidData, "Unable to decode toml file");
            Box::new(e) as Box<Error>
        })
    }

    pub fn save<T: Serialize>(value: &T, path: &Path) -> Result<(), Box<Error>> {
        if let Some(dir) = path.parent() {
            fs::create_dir_all(dir)?;
        }

        let mut file = File::create(path)?;
        file.write_all(&toml::ser::to_vec(&value)?)?;

        Ok(())
    }
}<commit_msg>add toml workaround<commit_after>use serde::{Serialize, Deserialize};
use toml;

use std::path::Path;
use std::io;
use std::fs;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;

pub struct ConfigFile {}

impl ConfigFile {
    pub fn load<T>(path: &Path) -> Result<T, Box<Error>>
        where T: for<'r> Deserialize<'r>
    {
        let mut file = File::open(path)?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        toml::de::from_str(&toml).map_err(|_| {
            let e = io::Error::new(io::ErrorKind::InvalidData, "Unable to decode toml file");
            Box::new(e) as Box<Error>
        })
    }

    pub fn save<T: Serialize>(value: &T, path: &Path) -> Result<(), Box<Error>> {
        if let Some(dir) = path.parent() {
            fs::create_dir_all(dir)?;
        }

        let mut file = File::create(path)?;
        let value_toml = toml::Value::try_from(value)?;
        file.write_all(&format!("{}", value_toml).into_bytes())?;

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