<commit_before>#![allow(non_snake_case)]

/// Extracted from [CMSIS 5]'s CMSIS/Core/Include/cmsis_gcc.h
///
/// [CMSIS 5]: https://github.com/ARM-software/CMSIS_5

/* Core function access */

/// Enable IRQ Interrupts
///
/// Enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be
/// executed in Privileged modes.
#[inline(always)]
pub unsafe fn __enable_irq() {
    asm!("cpsie i" : : : "memory" : "volatile");
}

/// Disable IRQ Interrupts
///
/// Disables IRQ interrupts by setting the I-bit in the CPSR. Can only be
/// executed in Privileged modes.
#[inline(always)]
pub unsafe fn __disable_irq() {
    asm!("cpsid i" : : : "memory" : "volatile");
}

/// Get Control Register
///
/// Returns the content of the Control Register.
#[inline(always)]
pub unsafe fn __get_CONTROL() -> u32 {
    let result: u32;
    asm!("mrs $0, CONTROL" : "=r"(result) : : : "volatile");
    result
}

/// Set Control Register
///
/// Writes the given value to the Control Register.
#[inline(always)]
pub unsafe fn __set_CONTROL(control: u32) {
    asm!("msr CONTROL, $0" : : "r"(control) : "memory" : "volatile");
}

/// Get IPSR Register
///
/// Returns the content of the IPSR Register.
#[inline(always)]
pub unsafe fn __get_IPSR() -> u32 {
    let result: u32;
    asm!("mrs $0, IPSR" : "=r"(result) : : : "volatile");
    result
}

/// Get APSR Register
///
/// Returns the content of the APSR Register.
#[inline(always)]
pub unsafe fn __get_APSR() -> u32 {
    let result: u32;
    asm!("mrs $0, APSR" : "=r"(result) : : : "volatile");
    result
}

/// Get xPSR Register
///
/// Returns the content of the xPSR Register.
#[inline(always)]
pub unsafe fn __get_xPSR() -> u32 {
    let result: u32;
    asm!("mrs $0, XPSR" : "=r"(result) : : : "volatile");
    result
}

/// Get Process Stack Pointer
///
/// Returns the current value of the Process Stack Pointer (PSP).
#[inline(always)]
pub unsafe fn __get_PSP() -> u32 {
    let result: u32;
    asm!("mrs $0, PSP" : "=r"(result) : : : "volatile");
    result
}

/// Set Process Stack Pointer
///
/// Assigns the given value to the Process Stack Pointer (PSP).
#[inline(always)]
pub unsafe fn __set_PSP(top_of_proc_stack: u32) {
    asm!("msr PSP, $0" : : "r"(top_of_proc_stack) : : "volatile");
}

/// Get Main Stack Pointer
///
/// Returns the current value of the Main Stack Pointer (MSP).
#[inline(always)]
pub unsafe fn __get_MSP() -> u32 {
    let result: u32;
    asm!("mrs $0, MSP" : "=r"(result) : : : "volatile");
    result
}

/// Set Main Stack Pointer
///
/// Assigns the given value to the Main Stack Pointer (MSP).
#[inline(always)]
pub unsafe fn __set_MSP(top_of_main_stack: u32) {
    asm!("msr MSP, $0" : : "r"(top_of_main_stack) : : "volatile");
}

/// Get Priority Mask
///
/// Returns the current state of the priority mask bit from the Priority Mask
/// Register.
#[inline(always)]
pub unsafe fn __get_PRIMASK() -> u32 {
    let result: u32;
    asm!("mrs $0, PRIMASK" : "=r"(result) : : "memory" : "volatile");
    result
}

/// Set Priority Mask
///
/// Assigns the given value to the Priority Mask Register.
#[inline(always)]
pub unsafe fn __set_PRIMASK(pri_mask: u32) {
    asm!("msr PRIMASK, $0" : : "r"(pri_mask) : : "volatile");
}

#[cfg(target_feature = "v7")]
mod v7 {
    /// Enable FIQ
    ///
    /// Enables FIQ interrupts by clearing the F-bit in the CPSR. Can only be
    /// executed in Privileged modes.
    #[inline(always)]
    pub unsafe fn __enable_fault_irq() {
        asm!("cpsie f" : : : "memory" : "volatile");
    }

    /// Disable FIQ
    ///
    /// Disables FIQ interrupts by setting the F-bit in the CPSR. Can only be
    /// executed in Privileged modes.
    #[inline(always)]
    pub unsafe fn __disable_fault_irq() {
        asm!("cpsid f" : : : "memory" : "volatile");
    }

    /// Get Base Priority
    ///
    /// Returns the current value of the Base Priority register.
    #[inline(always)]
    pub unsafe fn __get_BASEPRI() -> u32 {
        let result: u32;
        asm!("mrs $0, BASEPRI" : "=r"(result) : : : "volatile");
        result
    }

    /// Set Base Priority
    ///
    /// Assigns the given value to the Base Priority register.
    #[inline(always)]
    pub unsafe fn __set_BASEPRI(base_pri: u32) {
        asm!("msr BASEPRI, $0" : : "r"(base_pri) : "memory" : "volatile");
    }

    /// Set Base Priority with condition
    ///
    /// Assigns the given value to the Base Priority register only if BASEPRI
    /// masking is disabled, or the new value increases the BASEPRI
    /// priority level.
    #[inline(always)]
    pub unsafe fn __set_BASEPRI_MAX(base_pri: u32) {
        asm!("msr BASEPRI_MAX, $0" : : "r"(base_pri) : "memory" : "volatile");
    }

    /// Get Fault Mask
    ///
    /// Returns the current value of the Fault Mask register.
    #[inline(always)]
    pub unsafe fn __get_FAULTMASK() -> u32 {
        let result: u32;
        asm!("mrs $0, FAULTMASK" : "=r"(result) : : : "volatile");
        result
    }

    /// Set Fault Mask
    ///
    /// Assigns the given value to the Fault Mask register.
    #[inline(always)]
    pub unsafe fn __set_FAULTMASK(fault_mask: u32) {
        asm!("msr FAULTMASK, $0" : : "r"(fault_mask) : "memory" : "volatile");
    }
}

#[cfg(target_feature = "v7")]
pub use self::v7::*;

/* Core instruction access */

/// No Operation
///
/// No Operation does nothing. This instruction can be used for code alignment
/// purposes.
#[inline(always)]
pub unsafe fn __NOP() {
    asm!("nop" : : : : "volatile");
}

/// Wait For Interrupt
///
/// Wait For Interrupt is a hint instruction that suspends execution until one
/// of a number of events occurs.
#[inline(always)]
pub unsafe fn __WFI() {
    asm!("wfi" : : : : "volatile");
}

/// Wait For Event
///
/// Wait For Event is a hint instruction that permits the processor to enter a
/// low-power state until one of a number of events occurs.
#[inline(always)]
pub unsafe fn __WFE() {
    asm!("wfe" : : : : "volatile");
}

/// Send Event
///
/// Send Event is a hint instruction. It causes an event to be signaled to the
/// CPU.
#[inline(always)]
pub unsafe fn __SEV() {
    asm!("sev" : : : : "volatile");
}

/// Instruction Synchronization Barrier
///
/// Instruction Synchronization Barrier flushes the pipeline in the processor,
/// so that all instructions following the ISB are fetched from cache or
/// memory, after the instruction has been completed.
#[inline(always)]
pub unsafe fn __ISB() {
    asm!("isb 0xF" : : : "memory" : "volatile");
}

/// Data Synchronization Barrier
///
/// Acts as a special kind of Data Memory Barrier. It completes when all
/// explicit memory accesses before this instruction complete.
#[inline(always)]
pub unsafe fn __DSB() {
    asm!("dsb 0xF" : : : "memory" : "volatile");
}

/// Data Memory Barrier
///
/// Ensures the apparent order of the explicit memory operations before and
/// after the instruction, without ensuring their completion.
#[inline(always)]
pub unsafe fn __DMB() {
    asm!("dmb 0xF" : : : "memory" : "volatile");
}
<commit_msg>add #[target_feature(enable = ...)]<commit_after>#![allow(non_snake_case)]

/// Extracted from [CMSIS 5]'s CMSIS/Core/Include/cmsis_gcc.h
///
/// [CMSIS 5]: https://github.com/ARM-software/CMSIS_5

/* Core function access */

/// Enable IRQ Interrupts
///
/// Enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be
/// executed in Privileged modes.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __enable_irq() {
    asm!("cpsie i" : : : "memory" : "volatile");
}

/// Disable IRQ Interrupts
///
/// Disables IRQ interrupts by setting the I-bit in the CPSR. Can only be
/// executed in Privileged modes.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __disable_irq() {
    asm!("cpsid i" : : : "memory" : "volatile");
}

/// Get Control Register
///
/// Returns the content of the Control Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_CONTROL() -> u32 {
    let result: u32;
    asm!("mrs $0, CONTROL" : "=r"(result) : : : "volatile");
    result
}

/// Set Control Register
///
/// Writes the given value to the Control Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __set_CONTROL(control: u32) {
    asm!("msr CONTROL, $0" : : "r"(control) : "memory" : "volatile");
}

/// Get IPSR Register
///
/// Returns the content of the IPSR Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_IPSR() -> u32 {
    let result: u32;
    asm!("mrs $0, IPSR" : "=r"(result) : : : "volatile");
    result
}

/// Get APSR Register
///
/// Returns the content of the APSR Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_APSR() -> u32 {
    let result: u32;
    asm!("mrs $0, APSR" : "=r"(result) : : : "volatile");
    result
}

/// Get xPSR Register
///
/// Returns the content of the xPSR Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_xPSR() -> u32 {
    let result: u32;
    asm!("mrs $0, XPSR" : "=r"(result) : : : "volatile");
    result
}

/// Get Process Stack Pointer
///
/// Returns the current value of the Process Stack Pointer (PSP).
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_PSP() -> u32 {
    let result: u32;
    asm!("mrs $0, PSP" : "=r"(result) : : : "volatile");
    result
}

/// Set Process Stack Pointer
///
/// Assigns the given value to the Process Stack Pointer (PSP).
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __set_PSP(top_of_proc_stack: u32) {
    asm!("msr PSP, $0" : : "r"(top_of_proc_stack) : : "volatile");
}

/// Get Main Stack Pointer
///
/// Returns the current value of the Main Stack Pointer (MSP).
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_MSP() -> u32 {
    let result: u32;
    asm!("mrs $0, MSP" : "=r"(result) : : : "volatile");
    result
}

/// Set Main Stack Pointer
///
/// Assigns the given value to the Main Stack Pointer (MSP).
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __set_MSP(top_of_main_stack: u32) {
    asm!("msr MSP, $0" : : "r"(top_of_main_stack) : : "volatile");
}

/// Get Priority Mask
///
/// Returns the current state of the priority mask bit from the Priority Mask
/// Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __get_PRIMASK() -> u32 {
    let result: u32;
    asm!("mrs $0, PRIMASK" : "=r"(result) : : "memory" : "volatile");
    result
}

/// Set Priority Mask
///
/// Assigns the given value to the Priority Mask Register.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __set_PRIMASK(pri_mask: u32) {
    asm!("msr PRIMASK, $0" : : "r"(pri_mask) : : "volatile");
}

#[cfg(target_feature = "v7")]
mod v7 {
    /// Enable FIQ
    ///
    /// Enables FIQ interrupts by clearing the F-bit in the CPSR. Can only be
    /// executed in Privileged modes.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __enable_fault_irq() {
        asm!("cpsie f" : : : "memory" : "volatile");
    }

    /// Disable FIQ
    ///
    /// Disables FIQ interrupts by setting the F-bit in the CPSR. Can only be
    /// executed in Privileged modes.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __disable_fault_irq() {
        asm!("cpsid f" : : : "memory" : "volatile");
    }

    /// Get Base Priority
    ///
    /// Returns the current value of the Base Priority register.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __get_BASEPRI() -> u32 {
        let result: u32;
        asm!("mrs $0, BASEPRI" : "=r"(result) : : : "volatile");
        result
    }

    /// Set Base Priority
    ///
    /// Assigns the given value to the Base Priority register.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __set_BASEPRI(base_pri: u32) {
        asm!("msr BASEPRI, $0" : : "r"(base_pri) : "memory" : "volatile");
    }

    /// Set Base Priority with condition
    ///
    /// Assigns the given value to the Base Priority register only if BASEPRI
    /// masking is disabled, or the new value increases the BASEPRI
    /// priority level.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __set_BASEPRI_MAX(base_pri: u32) {
        asm!("msr BASEPRI_MAX, $0" : : "r"(base_pri) : "memory" : "volatile");
    }

    /// Get Fault Mask
    ///
    /// Returns the current value of the Fault Mask register.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __get_FAULTMASK() -> u32 {
        let result: u32;
        asm!("mrs $0, FAULTMASK" : "=r"(result) : : : "volatile");
        result
    }

    /// Set Fault Mask
    ///
    /// Assigns the given value to the Fault Mask register.
    #[inline]
    #[target_feature(enable = "mclass")]
    pub unsafe fn __set_FAULTMASK(fault_mask: u32) {
        asm!("msr FAULTMASK, $0" : : "r"(fault_mask) : "memory" : "volatile");
    }
}

#[cfg(target_feature = "v7")]
pub use self::v7::*;

/* Core instruction access */

/// No Operation
///
/// No Operation does nothing. This instruction can be used for code alignment
/// purposes.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __NOP() {
    asm!("nop" : : : : "volatile");
}

/// Wait For Interrupt
///
/// Wait For Interrupt is a hint instruction that suspends execution until one
/// of a number of events occurs.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __WFI() {
    asm!("wfi" : : : : "volatile");
}

/// Wait For Event
///
/// Wait For Event is a hint instruction that permits the processor to enter a
/// low-power state until one of a number of events occurs.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __WFE() {
    asm!("wfe" : : : : "volatile");
}

/// Send Event
///
/// Send Event is a hint instruction. It causes an event to be signaled to the
/// CPU.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __SEV() {
    asm!("sev" : : : : "volatile");
}

/// Instruction Synchronization Barrier
///
/// Instruction Synchronization Barrier flushes the pipeline in the processor,
/// so that all instructions following the ISB are fetched from cache or
/// memory, after the instruction has been completed.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __ISB() {
    asm!("isb 0xF" : : : "memory" : "volatile");
}

/// Data Synchronization Barrier
///
/// Acts as a special kind of Data Memory Barrier. It completes when all
/// explicit memory accesses before this instruction complete.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __DSB() {
    asm!("dsb 0xF" : : : "memory" : "volatile");
}

/// Data Memory Barrier
///
/// Ensures the apparent order of the explicit memory operations before and
/// after the instruction, without ensuring their completion.
#[inline]
#[target_feature(enable = "mclass")]
pub unsafe fn __DMB() {
    asm!("dmb 0xF" : : : "memory" : "volatile");
}
<|endoftext|>


<commit_before>//! Completes mod declarations.

use base_db::{SourceDatabaseExt, VfsPath};
use hir::{Module, ModuleSource};
use ide_db::RootDatabase;

use super::{completion_context::CompletionContext, completion_item::Completions};

/// Complete mod declaration, i.e. `mod <|> ;`
pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let current_module = ctx.scope.module()?;

    // TODO kb filter out declarations in possible_sudmobule_names
    // let declaration_source = current_module.declaration_source(ctx.db);
    let module_definition_source_file =
        current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
    let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_source_file));
    let directory_to_look_for_submodules = directory_to_look_for_submodules(
        current_module,
        ctx.db,
        source_root.path_for_file(&module_definition_source_file)?,
    )?;

    let mod_declaration_candidates = source_root
        .iter()
        .filter(|submodule_file| submodule_file != &module_definition_source_file)
        .filter_map(|submodule_file| {
            let submodule_path = source_root.path_for_file(&submodule_file)?;
            if submodule_path.parent()? == directory_to_look_for_submodules {
                submodule_path.file_name_and_extension()
            } else {
                None
            }
        })
        .filter_map(|file_name_and_extension| {
            match file_name_and_extension {
                // TODO kb in src/bin when a module is included into another,
                // the included file gets "moved" into a directory below and now cannot add any other modules
                ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None,
                (file_name, Some("rs")) => Some(file_name.to_owned()),
                (subdirectory_name, None) => {
                    let mod_rs_path =
                        directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
                    if source_root.file_for_path(&mod_rs_path).is_some() {
                        Some(subdirectory_name.to_owned())
                    } else {
                        None
                    }
                }
                _ => None,
            }
        })
        .collect::<Vec<_>>();
    dbg!(mod_declaration_candidates);

    // TODO kb exlude existing children from the candidates
    let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();

    Some(())
}

fn directory_to_look_for_submodules(
    module: Module,
    db: &RootDatabase,
    module_file_path: &VfsPath,
) -> Option<VfsPath> {
    let module_directory_path = module_file_path.parent()?;

    let base_directory = match module_file_path.file_name_and_extension()? {
        ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => {
            Some(module_directory_path)
        }
        (regular_rust_file_name, Some("rs")) => {
            if matches!(
                (
                    module_directory_path
                        .parent()
                        .as_ref()
                        .and_then(|path| path.file_name_and_extension()),
                    module_directory_path.file_name_and_extension(),
                ),
                (Some(("src", None)), Some(("bin", None)))
            ) {
                // files in /src/bin/ can import each other directly
                Some(module_directory_path)
            } else {
                module_directory_path.join(regular_rust_file_name)
            }
        }
        _ => None,
    }?;

    let mut resulting_path = base_directory;
    for module in module_chain_to_containing_module_file(module, db) {
        if let Some(name) = module.name(db) {
            resulting_path = resulting_path.join(&name.to_string())?;
        }
    }

    Some(resulting_path)
}

fn module_chain_to_containing_module_file(
    current_module: Module,
    db: &RootDatabase,
) -> Vec<Module> {
    let mut path = Vec::new();

    let mut current_module = Some(current_module);
    while let Some(ModuleSource::Module(_)) =
        current_module.map(|module| module.definition_source(db).value)
    {
        if let Some(module) = current_module {
            path.insert(0, module);
            current_module = module.parent(db);
        } else {
            current_module = None;
        }
    }

    path
}
<commit_msg>Less false positive completion candidates<commit_after>//! Completes mod declarations.

use base_db::{SourceDatabaseExt, VfsPath};
use hir::{Module, ModuleSource};
use ide_db::RootDatabase;
use rustc_hash::FxHashSet;

use super::{completion_context::CompletionContext, completion_item::Completions};

/// Complete mod declaration, i.e. `mod <|> ;`
pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    let current_module = ctx.scope.module()?;

    let module_definition_file =
        current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
    let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_file));
    let directory_to_look_for_submodules = directory_to_look_for_submodules(
        current_module,
        ctx.db,
        source_root.path_for_file(&module_definition_file)?,
    )?;

    let existing_mod_declarations = current_module
        .children(ctx.db)
        .filter_map(|module| Some(module.name(ctx.db)?.to_string()))
        .collect::<FxHashSet<_>>();

    let module_declaration_file =
        current_module.declaration_source(ctx.db).map(|module_declaration_source_file| {
            module_declaration_source_file.file_id.original_file(ctx.db)
        });

    let mod_declaration_candidates = source_root
        .iter()
        .filter(|submodule_candidate_file| submodule_candidate_file != &module_definition_file)
        .filter(|submodule_candidate_file| {
            Some(submodule_candidate_file) != module_declaration_file.as_ref()
        })
        .filter_map(|submodule_file| {
            let submodule_path = source_root.path_for_file(&submodule_file)?;
            if !is_special_rust_file_path(&submodule_path)
                && submodule_path.parent()? == directory_to_look_for_submodules
            {
                submodule_path.file_name_and_extension()
            } else {
                None
            }
        })
        .filter_map(|submodule_file_name_and_extension| match submodule_file_name_and_extension {
            (file_name, Some("rs")) => Some(file_name.to_owned()),
            (subdirectory_name, None) => {
                let mod_rs_path =
                    directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
                if source_root.file_for_path(&mod_rs_path).is_some() {
                    Some(subdirectory_name.to_owned())
                } else {
                    None
                }
            }
            _ => None,
        })
        .filter(|name| !existing_mod_declarations.contains(name))
        .collect::<Vec<_>>();
    dbg!(mod_declaration_candidates);

    // TODO kb exlude existing children from the candidates

    Some(())
}

fn is_special_rust_file_path(path: &VfsPath) -> bool {
    matches!(
        path.file_name_and_extension(),
        Some(("mod", Some("rs"))) | Some(("lib", Some("rs"))) | Some(("main", Some("rs")))
    )
}

fn directory_to_look_for_submodules(
    module: Module,
    db: &RootDatabase,
    module_file_path: &VfsPath,
) -> Option<VfsPath> {
    let module_directory_path = module_file_path.parent()?;
    let base_directory = if is_special_rust_file_path(module_file_path) {
        Some(module_directory_path)
    } else if let (regular_rust_file_name, Some("rs")) =
        module_file_path.file_name_and_extension()?
    {
        if matches!(
            (
                module_directory_path
                    .parent()
                    .as_ref()
                    .and_then(|path| path.file_name_and_extension()),
                module_directory_path.file_name_and_extension(),
            ),
            (Some(("src", None)), Some(("bin", None)))
        ) {
            // files in /src/bin/ can import each other directly
            Some(module_directory_path)
        } else {
            module_directory_path.join(regular_rust_file_name)
        }
    } else {
        None
    }?;

    let mut resulting_path = base_directory;
    for module in module_chain_to_containing_module_file(module, db) {
        if let Some(name) = module.name(db) {
            resulting_path = resulting_path.join(&name.to_string())?;
        }
    }

    Some(resulting_path)
}

fn module_chain_to_containing_module_file(
    current_module: Module,
    db: &RootDatabase,
) -> Vec<Module> {
    let mut path = Vec::new();

    let mut current_module = Some(current_module);
    while let Some(ModuleSource::Module(_)) =
        current_module.map(|module| module.definition_source(db).value)
    {
        if let Some(module) = current_module {
            path.insert(0, module);
            current_module = module.parent(db);
        } else {
            current_module = None;
        }
    }

    path
}
<|endoftext|>


<commit_before>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;

use crate::{
    HirDatabase, Module, Crate, Name, Function, Trait,
    impl_block::{ImplId, ImplBlock, ImplItem},
    ty::{Ty, TypeCtor},
    nameres::CrateModuleId,
    resolve::Resolver,
    traits::TraitItem,
    generics::HasGenericParams,
    ty::primitive::{UncertainIntTy, UncertainFloatTy}
};
use super::{TraitRef, Canonical, autoderef};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Apply(TypeCtor),
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the CrateModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        tr: &Trait,
    ) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
        let module_impl_blocks = db.impls_in_module(module.clone());

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id);

            let target_ty = impl_block.target_ty(db);

            if impl_block.target_trait(db).is_some() {
                if let Some(tr) = impl_block.target_trait_ref(db) {
                    self.impls_by_trait
                        .entry(tr.trait_)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            } else {
                if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                    self.impls
                        .entry(target_ty_fp)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, &child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, &module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
    macro_rules! lang_item_crate {
        ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
            let mut v = ArrayVec::<[Crate; 2]>::new();
            $(
                v.push($db.lang_item($cur_crate, $name.into())?.krate($db)?);
            )+
            Some(v)
        }};
    }

    match ty {
        Ty::Apply(a_ty) => match a_ty.ctor {
            TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
            TypeCtor::Bool => lang_item_crate![db, cur_crate, "bool"],
            TypeCtor::Char => lang_item_crate![db, cur_crate, "char"],
            TypeCtor::Float(UncertainFloatTy::Known(f)) => {
                lang_item_crate![db, cur_crate, f.ty_to_string()]
            }
            TypeCtor::Int(UncertainIntTy::Known(i)) => {
                lang_item_crate![db, cur_crate, i.ty_to_string()]
            }
            TypeCtor::Str => lang_item_crate![db, cur_crate, "str"],
            TypeCtor::Slice => lang_item_crate![db, cur_crate, "slice_alloc", "slice"],
            _ => None,
        },
        _ => None,
    }
}

/// Look up the method with the given name, returning the actual autoderefed
/// receiver type (but without autoref applied yet).
pub(crate) fn lookup_method(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: &Name,
    resolver: &Resolver,
) -> Option<(Ty, Function)> {
    iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
}

// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
pub(crate) fn iterate_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    // For method calls, rust first does any number of autoderef, and then one
    // autoref (i.e. when the method takes &self or &mut self). We just ignore
    // the autoref currently -- when we find a method matching the given name,
    // we assume it fits.

    // Also note that when we've got a receiver like &S, even if the method we
    // find in the end takes &self, we still do the autoderef step (just as
    // rustc does an autoderef and then autoref again).

    let krate = resolver.krate()?;
    for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
        if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
        {
            return Some(result);
        }
        if let Some(result) =
            iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
        {
            return Some(result);
        }
    }
    None
}

fn iterate_trait_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    let krate = resolver.krate()?;
    'traits: for t in resolver.traits_in_scope(db) {
        let data = t.trait_data(db);
        // we'll be lazy about checking whether the type implements the
        // trait, but if we find out it doesn't, we'll skip the rest of the
        // iteration
        let mut known_implemented = false;
        for item in data.items() {
            if let TraitItem::Function(m) = *item {
                let data = m.data(db);
                if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                    if !known_implemented {
                        let trait_ref = canonical_trait_ref(db, t, ty.clone());
                        if db.implements(krate, trait_ref).is_none() {
                            continue 'traits;
                        }
                    }
                    known_implemented = true;
                    if let Some(result) = callback(&ty.value, m) {
                        return Some(result);
                    }
                }
            }
        }
    }
    None
}

fn iterate_inherent_methods<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: Option<&Name>,
    krate: Crate,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    for krate in def_crates(db, krate, &ty.value)? {
        let impls = db.impls_in_crate(krate);

        for impl_block in impls.lookup_impl_blocks(&ty.value) {
            for item in impl_block.items(db) {
                if let ImplItem::Method(f) = item {
                    let data = f.data(db);
                    if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                        if let Some(result) = callback(&ty.value, f) {
                            return Some(result);
                        }
                    }
                }
            }
        }
    }
    None
}

impl Ty {
    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_impl_items<T>(
        self,
        db: &impl HirDatabase,
        krate: Crate,
        mut callback: impl FnMut(ImplItem) -> Option<T>,
    ) -> Option<T> {
        for krate in def_crates(db, krate, &self)? {
            let impls = db.impls_in_crate(krate);

            for impl_block in impls.lookup_impl_blocks(&self) {
                for item in impl_block.items(db) {
                    if let Some(result) = callback(item) {
                        return Some(result);
                    }
                }
            }
        }
        None
    }
}

/// This creates Substs for a trait with the given Self type and type variables
/// for all other parameters, to query Chalk with it.
fn canonical_trait_ref(
    db: &impl HirDatabase,
    trait_: Trait,
    self_ty: Canonical<Ty>,
) -> Canonical<TraitRef> {
    let mut substs = Vec::new();
    let generics = trait_.generic_params(db);
    let num_vars = self_ty.num_vars;
    substs.push(self_ty.value);
    substs.extend(
        generics
            .params_including_parent()
            .into_iter()
            .skip(1)
            .enumerate()
            .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
    );
    Canonical {
        num_vars: substs.len() - 1 + self_ty.num_vars,
        value: TraitRef { trait_, substs: substs.into() },
    }
}
<commit_msg>Add comment<commit_after>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use arrayvec::ArrayVec;
use rustc_hash::FxHashMap;

use crate::{
    HirDatabase, Module, Crate, Name, Function, Trait,
    impl_block::{ImplId, ImplBlock, ImplItem},
    ty::{Ty, TypeCtor},
    nameres::CrateModuleId,
    resolve::Resolver,
    traits::TraitItem,
    generics::HasGenericParams,
    ty::primitive::{UncertainIntTy, UncertainFloatTy}
};
use super::{TraitRef, Canonical, autoderef};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Apply(TypeCtor),
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the CrateModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        tr: &Trait,
    ) -> impl Iterator<Item = ImplBlock> + 'a {
        self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                ImplBlock::from_id(module, *impl_id)
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
        let module_impl_blocks = db.impls_in_module(module.clone());

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id);

            let target_ty = impl_block.target_ty(db);

            if impl_block.target_trait(db).is_some() {
                if let Some(tr) = impl_block.target_trait_ref(db) {
                    self.impls_by_trait
                        .entry(tr.trait_)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            } else {
                if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                    self.impls
                        .entry(target_ty_fp)
                        .or_insert_with(Vec::new)
                        .push((module.module_id, impl_id));
                }
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, &child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, &module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
    // Types like slice can have inherent impls in several crates, (core and alloc).
    // The correspoinding impls are marked with lang items, so we can use them to find the required crates.
    macro_rules! lang_item_crate {
        ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
            let mut v = ArrayVec::<[Crate; 2]>::new();
            $(
                v.push($db.lang_item($cur_crate, $name.into())?.krate($db)?);
            )+
            Some(v)
        }};
    }

    match ty {
        Ty::Apply(a_ty) => match a_ty.ctor {
            TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
            TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
            TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
            TypeCtor::Float(UncertainFloatTy::Known(f)) => {
                lang_item_crate!(db, cur_crate, f.ty_to_string())
            }
            TypeCtor::Int(UncertainIntTy::Known(i)) => {
                lang_item_crate!(db, cur_crate, i.ty_to_string())
            }
            TypeCtor::Str => lang_item_crate!(db, cur_crate, "str"),
            TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"),
            _ => None,
        },
        _ => None,
    }
}

/// Look up the method with the given name, returning the actual autoderefed
/// receiver type (but without autoref applied yet).
pub(crate) fn lookup_method(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: &Name,
    resolver: &Resolver,
) -> Option<(Ty, Function)> {
    iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
}

// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
pub(crate) fn iterate_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    // For method calls, rust first does any number of autoderef, and then one
    // autoref (i.e. when the method takes &self or &mut self). We just ignore
    // the autoref currently -- when we find a method matching the given name,
    // we assume it fits.

    // Also note that when we've got a receiver like &S, even if the method we
    // find in the end takes &self, we still do the autoderef step (just as
    // rustc does an autoderef and then autoref again).

    let krate = resolver.krate()?;
    for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
        if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
        {
            return Some(result);
        }
        if let Some(result) =
            iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
        {
            return Some(result);
        }
    }
    None
}

fn iterate_trait_method_candidates<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    resolver: &Resolver,
    name: Option<&Name>,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    let krate = resolver.krate()?;
    'traits: for t in resolver.traits_in_scope(db) {
        let data = t.trait_data(db);
        // we'll be lazy about checking whether the type implements the
        // trait, but if we find out it doesn't, we'll skip the rest of the
        // iteration
        let mut known_implemented = false;
        for item in data.items() {
            if let TraitItem::Function(m) = *item {
                let data = m.data(db);
                if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                    if !known_implemented {
                        let trait_ref = canonical_trait_ref(db, t, ty.clone());
                        if db.implements(krate, trait_ref).is_none() {
                            continue 'traits;
                        }
                    }
                    known_implemented = true;
                    if let Some(result) = callback(&ty.value, m) {
                        return Some(result);
                    }
                }
            }
        }
    }
    None
}

fn iterate_inherent_methods<T>(
    ty: &Canonical<Ty>,
    db: &impl HirDatabase,
    name: Option<&Name>,
    krate: Crate,
    mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
    for krate in def_crates(db, krate, &ty.value)? {
        let impls = db.impls_in_crate(krate);

        for impl_block in impls.lookup_impl_blocks(&ty.value) {
            for item in impl_block.items(db) {
                if let ImplItem::Method(f) = item {
                    let data = f.data(db);
                    if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
                        if let Some(result) = callback(&ty.value, f) {
                            return Some(result);
                        }
                    }
                }
            }
        }
    }
    None
}

impl Ty {
    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_impl_items<T>(
        self,
        db: &impl HirDatabase,
        krate: Crate,
        mut callback: impl FnMut(ImplItem) -> Option<T>,
    ) -> Option<T> {
        for krate in def_crates(db, krate, &self)? {
            let impls = db.impls_in_crate(krate);

            for impl_block in impls.lookup_impl_blocks(&self) {
                for item in impl_block.items(db) {
                    if let Some(result) = callback(item) {
                        return Some(result);
                    }
                }
            }
        }
        None
    }
}

/// This creates Substs for a trait with the given Self type and type variables
/// for all other parameters, to query Chalk with it.
fn canonical_trait_ref(
    db: &impl HirDatabase,
    trait_: Trait,
    self_ty: Canonical<Ty>,
) -> Canonical<TraitRef> {
    let mut substs = Vec::new();
    let generics = trait_.generic_params(db);
    let num_vars = self_ty.num_vars;
    substs.push(self_ty.value);
    substs.extend(
        generics
            .params_including_parent()
            .into_iter()
            .skip(1)
            .enumerate()
            .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
    );
    Canonical {
        num_vars: substs.len() - 1 + self_ty.num_vars,
        value: TraitRef { trait_, substs: substs.into() },
    }
}
<|endoftext|>


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

use std::cmp;
use std::ops::BitOr;
use format::Format;
use vk;

/// Describes a single descriptor.
#[derive(Debug, Copy, Clone)]
pub struct DescriptorDesc {
    /// Describes the content and layout of each array element of a descriptor.
    pub ty: DescriptorDescTy,

    /// How many array elements this descriptor is made of.
    pub array_count: u32,

    /// Which shader stages are going to access this descriptor.
    pub stages: ShaderStages,

    /// True if the attachment is only ever read by the shader. False if it is also written.
    pub readonly: bool,
}

impl DescriptorDesc {
    /// Checks whether we are a superset of another descriptor.
    ///
    /// This means that either the descriptor is the same, or it is the same but with a larger
    /// array elements count, or it is the same with more shader stages.
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorDesc) -> bool {
        self.ty.is_superset_of(&other.ty) &&
        self.array_count >= other.array_count && self.stages.is_superset_of(&other.stages) &&
        (!self.readonly || other.readonly)
    }

    /// Builds a `DescriptorDesc` that is the union of `self` and `other`.
    ///
    /// The returned value will be a superset of both `self` and `other`.
    // TODO: Result instead of Option
    #[inline]
    pub fn union(&self, other: &DescriptorDesc) -> Option<DescriptorDesc> {
        if self.ty != other.ty { return None; }

        Some(DescriptorDesc {
            ty: self.ty.clone(),
            array_count: cmp::max(self.array_count, other.array_count),
            stages: self.stages | other.stages,
            readonly: self.readonly && other.readonly,
        })
    }
}

/// Describes the content and layout of each array element of a descriptor.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorDescTy {
    Sampler,                // TODO: the sampler has some restrictions as well
    CombinedImageSampler(DescriptorImageDesc),               // TODO: the sampler has some restrictions as well
    Image(DescriptorImageDesc),
    TexelBuffer {
        /// If `true`, this describes a storage texel buffer.
        storage: bool,
        /// The format of the content, or `None` if the format is unknown. Depending on the
        /// context, it may be invalid to have a `None` value here.
        format: Option<Format>,
    },
    InputAttachment { multisampled: bool, array_layers: DescriptorImageDescArray },
    Buffer(DescriptorBufferDesc),
}

impl DescriptorDescTy {
    /// Returns the type of descriptor.
    ///
    /// Returns `None` if there's not enough info to determine the type.
    pub fn ty(&self) -> Option<DescriptorType> {
        Some(match *self {
            DescriptorDescTy::Sampler => DescriptorType::Sampler,
            DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
            DescriptorDescTy::Image(desc) => {
                if desc.sampled { DescriptorType::SampledImage }
                else { DescriptorType::StorageImage }
            },
            DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
            DescriptorDescTy::Buffer(desc) => {
                let dynamic = match desc.dynamic { Some(d) => d, None => return None };
                match (desc.storage, dynamic) {
                    (false, false) => DescriptorType::UniformBuffer,
                    (true, false) => DescriptorType::StorageBuffer,
                    (false, true) => DescriptorType::UniformBufferDynamic,
                    (true, true) => DescriptorType::StorageBufferDynamic,
                }
            },
            DescriptorDescTy::TexelBuffer { storage, .. } => {
                if storage { DescriptorType::StorageTexelBuffer }
                else { DescriptorType::UniformTexelBuffer }
            },
        })
    }

    /// Checks whether we are a superset of another descriptor type.
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorDescTy) -> bool {
        match (*self, *other) {
            (DescriptorDescTy::Sampler, DescriptorDescTy::Sampler) => true,

            (DescriptorDescTy::CombinedImageSampler(ref me),
             DescriptorDescTy::CombinedImageSampler(ref other)) => me.is_superset_of(other),

            (DescriptorDescTy::Image(ref me),
             DescriptorDescTy::Image(ref other)) => me.is_superset_of(other),

            (DescriptorDescTy::InputAttachment { multisampled: me_multisampled,
                                                 array_layers: me_array_layers },
             DescriptorDescTy::InputAttachment { multisampled: other_multisampled,
                                                 array_layers: other_array_layers }) =>
            {
                me_multisampled == other_multisampled && me_array_layers == other_array_layers
            },

            (DescriptorDescTy::Buffer(ref me), DescriptorDescTy::Buffer(ref other)) => {
                if me.storage != other.storage {
                    return false;
                }

                match (me.dynamic, other.dynamic) {
                    (Some(_), None) => true,
                    (Some(m), Some(o)) => m == o,
                    (None, None) => true,
                    (None, Some(_)) => false,
                }
            },

            (DescriptorDescTy::TexelBuffer { storage: me_storage, format: me_format },
             DescriptorDescTy::TexelBuffer { storage: other_storage, format: other_format }) =>
            {
                if me_storage != other_storage {
                    return false;
                }

                match (me_format, other_format) {
                    (Some(_), None) => true,
                    (Some(m), Some(o)) => m == o,
                    (None, None) => true,
                    (None, Some(_)) => false,
                }
            },

            // Any other combination is invalid.
            _ => false
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DescriptorImageDesc {
    pub sampled: bool,
    pub dimensions: DescriptorImageDescDimensions,
    /// The format of the image, or `None` if the format is unknown.
    pub format: Option<Format>,
    /// True if the image is multisampled.
    pub multisampled: bool,
    pub array_layers: DescriptorImageDescArray,
}

impl DescriptorImageDesc {
    /// Checks whether we are a superset of another image.
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorImageDesc) -> bool {
        if self.dimensions != other.dimensions {
            return false;
        }

        if self.multisampled != other.multisampled {
            return false;
        }

        match (self.format, other.format) {
            (Some(a), Some(b)) => if a != b { return false; },
            (Some(_), None) => (),
            (None, None) => (),
            (None, Some(_)) => return false,
        };

        match (self.array_layers, other.array_layers) {
            (DescriptorImageDescArray::NonArrayed, DescriptorImageDescArray::NonArrayed) => (),
            (DescriptorImageDescArray::Arrayed { max_layers: my_max },
             DescriptorImageDescArray::Arrayed { max_layers: other_max }) =>
            {
                match (my_max, other_max) {
                    (Some(m), Some(o)) => if m < o { return false; },
                    (Some(_), None) => (),
                    (None, _) => return false,
                };
            },
            _ => return false
        };

        true
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescArray {
    NonArrayed,
    Arrayed { max_layers: Option<u32> }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescDimensions {
    OneDimensional,
    TwoDimensional,
    ThreeDimensional,
    Cube,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DescriptorBufferDesc {
    pub dynamic: Option<bool>,
    pub storage: bool,
    // FIXME: store content
}

/// Describes what kind of resource may later be bound to a descriptor.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum DescriptorType {
    Sampler = vk::DESCRIPTOR_TYPE_SAMPLER,
    CombinedImageSampler = vk::DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
    SampledImage = vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE,
    StorageImage = vk::DESCRIPTOR_TYPE_STORAGE_IMAGE,
    UniformTexelBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
    StorageTexelBuffer = vk::DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
    UniformBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,
    StorageBuffer = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER,
    UniformBufferDynamic = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
    StorageBufferDynamic = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
    InputAttachment = vk::DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
}

/// Describes which shader stages have access to a descriptor.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderStages {
    /// `True` means that the descriptor will be used by the vertex shader.
    pub vertex: bool,
    /// `True` means that the descriptor will be used by the tessellation control shader.
    pub tessellation_control: bool,
    /// `True` means that the descriptor will be used by the tessellation evaluation shader.
    pub tessellation_evaluation: bool,
    /// `True` means that the descriptor will be used by the geometry shader.
    pub geometry: bool,
    /// `True` means that the descriptor will be used by the fragment shader.
    pub fragment: bool,
    /// `True` means that the descriptor will be used by the compute shader.
    pub compute: bool,
}

impl ShaderStages {
    /// Creates a `ShaderStages` struct will all stages set to `true`.
    #[inline]
    pub fn all() -> ShaderStages {
        ShaderStages {
            vertex: true,
            tessellation_control: true,
            tessellation_evaluation: true,
            geometry: true,
            fragment: true,
            compute: true,
        }
    }

    /// Creates a `ShaderStages` struct will all stages set to `false`.
    #[inline]
    pub fn none() -> ShaderStages {
        ShaderStages {
            vertex: false,
            tessellation_control: false,
            tessellation_evaluation: false,
            geometry: false,
            fragment: false,
            compute: false,
        }
    }

    /// Creates a `ShaderStages` struct will all graphics stages set to `true`.
    #[inline]
    pub fn all_graphics() -> ShaderStages {
        ShaderStages {
            vertex: true,
            tessellation_control: true,
            tessellation_evaluation: true,
            geometry: true,
            fragment: true,
            compute: false,
        }
    }

    /// Creates a `ShaderStages` struct will the compute stage set to `true`.
    #[inline]
    pub fn compute() -> ShaderStages {
        ShaderStages {
            vertex: false,
            tessellation_control: false,
            tessellation_evaluation: false,
            geometry: false,
            fragment: false,
            compute: true,
        }
    }

    /// Checks whether we have more stages enabled than `other`.
    #[inline]
    pub fn is_superset_of(&self, other: &ShaderStages) -> bool {
        (self.vertex || !other.vertex) &&
        (self.tessellation_control || !other.tessellation_control) &&
        (self.tessellation_evaluation || !other.tessellation_evaluation) &&
        (self.geometry || !other.geometry) &&
        (self.fragment || !other.fragment) &&
        (self.compute || !other.compute)
    }
}

impl BitOr for ShaderStages {
    type Output = ShaderStages;

    #[inline]
    fn bitor(self, other: ShaderStages) -> ShaderStages {
        ShaderStages {
            vertex: self.vertex || other.vertex,
            tessellation_control: self.tessellation_control || other.tessellation_control,
            tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
            geometry: self.geometry || other.geometry,
            fragment: self.fragment || other.fragment,
            compute: self.compute || other.compute,
        }
    }
}

#[doc(hidden)]
impl Into<vk::ShaderStageFlags> for ShaderStages {
    #[inline]
    fn into(self) -> vk::ShaderStageFlags {
        let mut result = 0;
        if self.vertex { result |= vk::SHADER_STAGE_VERTEX_BIT; }
        if self.tessellation_control { result |= vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT; }
        if self.tessellation_evaluation { result |= vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT; }
        if self.geometry { result |= vk::SHADER_STAGE_GEOMETRY_BIT; }
        if self.fragment { result |= vk::SHADER_STAGE_FRAGMENT_BIT; }
        if self.compute { result |= vk::SHADER_STAGE_COMPUTE_BIT; }
        result
    }
}
<commit_msg>Some documentation for descriptors module<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.

//! Description of a single descriptor.
//!
//! This module contains traits and structs related to describing a single descriptor. A descriptor
//! is a slot where you can bind a buffer or an image so that it can be accessed from your shaders.
//! In order to specify which buffer or image to bind to a descriptor, see the `descriptor_set`
//! module.
//!
//! There are four different kinds of descriptors that give access to buffers:
//!
//! - Uniform texel buffers. Gives read-only access to the content of a buffer. Only supports
//!   certain buffer formats.
//! - Storage texel buffers. Gives read and/or write access to the content of a buffer. Only
//!   supports certain buffer formats. Less restrictive but sometimes slower than uniform texel
//!   buffers.
//! - Uniform buffers. Gives read-only access to the content of a buffer. Less restrictive but
//!   sometimes slower than uniform texel buffers.
//! - Storage buffers. Gives read and/or write access to the content of a buffer. Less restrictive
//!   but sometimes slower than uniform buffers and storage texel buffers.
//!
//! There are five different kinds of descriptors related to images:
//!
//! - Storage images. Gives read and/or write access to individual pixels in an image. The image
//!   cannot be sampled. In other words, you have exactly specify which pixel to read or write.
//! - Sampled images. Gives read-only access to an image. Before you can use a sampled image in a
//!   a shader, you have to combine it with a sampler (see below). The sampler describes how
//!   reading the image will behave.
//! - Samplers. Doesn't contain an image but a sampler object that describes how an image will be
//!   accessed. This is meant to be combined with a sampled image (see above).
//! - Combined image and sampler. Similar to a sampled image, but also directly includes the
//!   sampler which indicates how the sampling is done.
//! - Input attachments. The fastest but also most restrictive access to images. Must be integrated
//!   in a render pass. Can only give access to the same pixel as the one you're processing.
//!

use std::cmp;
use std::ops::BitOr;
use format::Format;
use vk;

/// Contains the exact description of a single descriptor.
///
/// > **Note**: You are free to fill a `DescriptorDesc` struct the way you want, but its validity
/// > will be checked when you create a pipeline layout, a descriptor set, or when you try to bind
/// > a descriptor set.
// TODO: add example
#[derive(Debug, Copy, Clone)]
pub struct DescriptorDesc {
    /// Describes the content and layout of each array element of a descriptor.
    pub ty: DescriptorDescTy,

    /// How many array elements this descriptor is made of. The value 0 is invalid and may trigger
    /// a panic depending on the situation.
    pub array_count: u32,

    /// Which shader stages are going to access this descriptor.
    pub stages: ShaderStages,

    /// True if the attachment is only ever read by the shader. False if it is also written.
    pub readonly: bool,
}

impl DescriptorDesc {
    /// Checks whether we are a superset of another descriptor.
    ///
    /// Returns true if `self` is the same descriptor as `other`, or if `self` is the same as
    /// `other` but with a larger array elements count and/or more shader stages.
    // TODO: add example
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorDesc) -> bool {
        self.ty.is_superset_of(&other.ty) &&
        self.array_count >= other.array_count && self.stages.is_superset_of(&other.stages) &&
        (!self.readonly || other.readonly)
    }

    /// Builds a `DescriptorDesc` that is the union of `self` and `other`, if possible.
    ///
    /// The returned value will be a superset of both `self` and `other`.
    // TODO: Result instead of Option
    // TODO: add example
    #[inline]
    pub fn union(&self, other: &DescriptorDesc) -> Option<DescriptorDesc> {
        if self.ty != other.ty { return None; }

        Some(DescriptorDesc {
            ty: self.ty.clone(),
            array_count: cmp::max(self.array_count, other.array_count),
            stages: self.stages | other.stages,
            readonly: self.readonly && other.readonly,
        })
    }
}

/// Describes the content and layout of each array element of a descriptor.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorDescTy {
    Sampler,                // TODO: the sampler has some restrictions as well
    CombinedImageSampler(DescriptorImageDesc),               // TODO: the sampler has some restrictions as well
    Image(DescriptorImageDesc),
    TexelBuffer {
        /// If `true`, this describes a storage texel buffer.
        storage: bool,

        /// The format of the content, or `None` if the format is unknown. Depending on the
        /// context, it may be invalid to have a `None` value here. If the format is `Some`, only
        /// buffer views that have this exact format can be attached to this descriptor.
        format: Option<Format>,
    },
    InputAttachment {
        /// If `true`, the input attachment is multisampled. Only multisampled images can be
        /// attached to this descriptor.
        multisampled: bool,
        array_layers: DescriptorImageDescArray,
    },
    Buffer(DescriptorBufferDesc),
}

impl DescriptorDescTy {
    /// Returns the type of descriptor.
    ///
    /// Returns `None` if there's not enough info to determine the type.
    // TODO: add example
    pub fn ty(&self) -> Option<DescriptorType> {
        Some(match *self {
            DescriptorDescTy::Sampler => DescriptorType::Sampler,
            DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
            DescriptorDescTy::Image(desc) => {
                if desc.sampled { DescriptorType::SampledImage }
                else { DescriptorType::StorageImage }
            },
            DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
            DescriptorDescTy::Buffer(desc) => {
                let dynamic = match desc.dynamic { Some(d) => d, None => return None };
                match (desc.storage, dynamic) {
                    (false, false) => DescriptorType::UniformBuffer,
                    (true, false) => DescriptorType::StorageBuffer,
                    (false, true) => DescriptorType::UniformBufferDynamic,
                    (true, true) => DescriptorType::StorageBufferDynamic,
                }
            },
            DescriptorDescTy::TexelBuffer { storage, .. } => {
                if storage { DescriptorType::StorageTexelBuffer }
                else { DescriptorType::UniformTexelBuffer }
            },
        })
    }

    /// Checks whether we are a superset of another descriptor type.
    // TODO: add example
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorDescTy) -> bool {
        match (*self, *other) {
            (DescriptorDescTy::Sampler, DescriptorDescTy::Sampler) => true,

            (DescriptorDescTy::CombinedImageSampler(ref me),
             DescriptorDescTy::CombinedImageSampler(ref other)) => me.is_superset_of(other),

            (DescriptorDescTy::Image(ref me),
             DescriptorDescTy::Image(ref other)) => me.is_superset_of(other),

            (DescriptorDescTy::InputAttachment { multisampled: me_multisampled,
                                                 array_layers: me_array_layers },
             DescriptorDescTy::InputAttachment { multisampled: other_multisampled,
                                                 array_layers: other_array_layers }) =>
            {
                me_multisampled == other_multisampled && me_array_layers == other_array_layers
            },

            (DescriptorDescTy::Buffer(ref me), DescriptorDescTy::Buffer(ref other)) => {
                if me.storage != other.storage {
                    return false;
                }

                match (me.dynamic, other.dynamic) {
                    (Some(_), None) => true,
                    (Some(m), Some(o)) => m == o,
                    (None, None) => true,
                    (None, Some(_)) => false,
                }
            },

            (DescriptorDescTy::TexelBuffer { storage: me_storage, format: me_format },
             DescriptorDescTy::TexelBuffer { storage: other_storage, format: other_format }) =>
            {
                if me_storage != other_storage {
                    return false;
                }

                match (me_format, other_format) {
                    (Some(_), None) => true,
                    (Some(m), Some(o)) => m == o,
                    (None, None) => true,
                    (None, Some(_)) => false,
                }
            },

            // Any other combination is invalid.
            _ => false
        }
    }
}

/// Additional description for descriptors that contain images.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DescriptorImageDesc {
    /// If `true`, the image can be sampled by the shader. Only images that were created with the
    /// `sampled` usage can be attached to the descriptor.
    pub sampled: bool,
    /// The kind of image: one-dimensional, two-dimensional, three-dimensional, or cube.
    pub dimensions: DescriptorImageDescDimensions,
    /// The format of the image, or `None` if the format is unknown. If `Some`, only images with
    /// exactly that format can be attached.
    pub format: Option<Format>,
    /// True if the image is multisampled.
    pub multisampled: bool,
    /// Whether the descriptor contains one or more array layers of an image.
    pub array_layers: DescriptorImageDescArray,
}

impl DescriptorImageDesc {
    /// Checks whether we are a superset of another image.
    // TODO: add example
    #[inline]
    pub fn is_superset_of(&self, other: &DescriptorImageDesc) -> bool {
        if self.dimensions != other.dimensions {
            return false;
        }

        if self.multisampled != other.multisampled {
            return false;
        }

        match (self.format, other.format) {
            (Some(a), Some(b)) => if a != b { return false; },
            (Some(_), None) => (),
            (None, None) => (),
            (None, Some(_)) => return false,
        };

        match (self.array_layers, other.array_layers) {
            (DescriptorImageDescArray::NonArrayed, DescriptorImageDescArray::NonArrayed) => (),
            (DescriptorImageDescArray::Arrayed { max_layers: my_max },
             DescriptorImageDescArray::Arrayed { max_layers: other_max }) =>
            {
                match (my_max, other_max) {
                    (Some(m), Some(o)) => if m < o { return false; },
                    (Some(_), None) => (),
                    (None, _) => return false,
                };
            },
            _ => return false
        };

        true
    }
}

// TODO: documentation
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescArray {
    NonArrayed,
    Arrayed { max_layers: Option<u32> }
}

// TODO: documentation
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DescriptorImageDescDimensions {
    OneDimensional,
    TwoDimensional,
    ThreeDimensional,
    Cube,
}

// TODO: documentation
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DescriptorBufferDesc {
    pub dynamic: Option<bool>,
    pub storage: bool,
    // FIXME: store content
}

/// Describes what kind of resource may later be bound to a descriptor.
///
/// This is mostly the same as a `DescriptorDescTy` but with less precise information.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum DescriptorType {
    Sampler = vk::DESCRIPTOR_TYPE_SAMPLER,
    CombinedImageSampler = vk::DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
    SampledImage = vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE,
    StorageImage = vk::DESCRIPTOR_TYPE_STORAGE_IMAGE,
    UniformTexelBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
    StorageTexelBuffer = vk::DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
    UniformBuffer = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,
    StorageBuffer = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER,
    UniformBufferDynamic = vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
    StorageBufferDynamic = vk::DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
    InputAttachment = vk::DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
}

/// Describes which shader stages have access to a descriptor.
// TODO: add example with BitOr
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderStages {
    /// `True` means that the descriptor will be used by the vertex shader.
    pub vertex: bool,
    /// `True` means that the descriptor will be used by the tessellation control shader.
    pub tessellation_control: bool,
    /// `True` means that the descriptor will be used by the tessellation evaluation shader.
    pub tessellation_evaluation: bool,
    /// `True` means that the descriptor will be used by the geometry shader.
    pub geometry: bool,
    /// `True` means that the descriptor will be used by the fragment shader.
    pub fragment: bool,
    /// `True` means that the descriptor will be used by the compute shader.
    pub compute: bool,
}

impl ShaderStages {
    /// Creates a `ShaderStages` struct will all stages set to `true`.
    // TODO: add example
    #[inline]
    pub fn all() -> ShaderStages {
        ShaderStages {
            vertex: true,
            tessellation_control: true,
            tessellation_evaluation: true,
            geometry: true,
            fragment: true,
            compute: true,
        }
    }

    /// Creates a `ShaderStages` struct will all stages set to `false`.
    // TODO: add example
    #[inline]
    pub fn none() -> ShaderStages {
        ShaderStages {
            vertex: false,
            tessellation_control: false,
            tessellation_evaluation: false,
            geometry: false,
            fragment: false,
            compute: false,
        }
    }

    /// Creates a `ShaderStages` struct with all graphics stages set to `true`.
    // TODO: add example
    #[inline]
    pub fn all_graphics() -> ShaderStages {
        ShaderStages {
            vertex: true,
            tessellation_control: true,
            tessellation_evaluation: true,
            geometry: true,
            fragment: true,
            compute: false,
        }
    }

    /// Creates a `ShaderStages` struct with the compute stage set to `true`.
    // TODO: add example
    #[inline]
    pub fn compute() -> ShaderStages {
        ShaderStages {
            vertex: false,
            tessellation_control: false,
            tessellation_evaluation: false,
            geometry: false,
            fragment: false,
            compute: true,
        }
    }

    /// Checks whether we have more stages enabled than `other`.
    // TODO: add example
    #[inline]
    pub fn is_superset_of(&self, other: &ShaderStages) -> bool {
        (self.vertex || !other.vertex) &&
        (self.tessellation_control || !other.tessellation_control) &&
        (self.tessellation_evaluation || !other.tessellation_evaluation) &&
        (self.geometry || !other.geometry) &&
        (self.fragment || !other.fragment) &&
        (self.compute || !other.compute)
    }
}

impl BitOr for ShaderStages {
    type Output = ShaderStages;

    #[inline]
    fn bitor(self, other: ShaderStages) -> ShaderStages {
        ShaderStages {
            vertex: self.vertex || other.vertex,
            tessellation_control: self.tessellation_control || other.tessellation_control,
            tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
            geometry: self.geometry || other.geometry,
            fragment: self.fragment || other.fragment,
            compute: self.compute || other.compute,
        }
    }
}

#[doc(hidden)]
impl Into<vk::ShaderStageFlags> for ShaderStages {
    #[inline]
    fn into(self) -> vk::ShaderStageFlags {
        let mut result = 0;
        if self.vertex { result |= vk::SHADER_STAGE_VERTEX_BIT; }
        if self.tessellation_control { result |= vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT; }
        if self.tessellation_evaluation { result |= vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT; }
        if self.geometry { result |= vk::SHADER_STAGE_GEOMETRY_BIT; }
        if self.fragment { result |= vk::SHADER_STAGE_FRAGMENT_BIT; }
        if self.compute { result |= vk::SHADER_STAGE_COMPUTE_BIT; }
        result
    }
}
<|endoftext|>


<commit_before>//! Rust 版管理人形

// TODO: 最終的には外すこと
#![allow(dead_code)]
#![allow(unused_variables)]

mod sys;
mod sysmod;

use anyhow::{ensure, Context, Result};
use daemonize::Daemonize;
use getopts::Options;
use log::{error, info, warn, LevelFilter};
use simplelog::format_description;
use simplelog::{ColorChoice, TerminalMode};
use simplelog::{CombinedLogger, ConfigBuilder, SharedLogger, TermLogger, WriteLogger};
use std::env;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use sys::taskserver::{Control, TaskServer};
use sysmod::SystemModules;

use crate::sys::taskserver::RunResult;

/// デーモン化の際に指定する stdout のリダイレクト先。
const STDOUT_FILE: &str = "stdout.txt";
/// デーモン化の際に指定する stderr のリダイレクト先。
const STDERR_FILE: &str = "stderr.txt";
/// デーモン化の際に指定する pid ファイルパス。
const PID_FILE: &str = "rshanghai.pid";
/// ログのファイル出力先。
const LOG_FILE: &str = "rshanghai.log";

/// デフォルトの設定データ(json source)。
/// [include_str!] でバイナリに含める。
const DEF_CONFIG_JSON: &str = include_str!("res/config_default.json");
const TW_CONTENTS_JSON: &str = include_str!("res/tw_contents.json");
const CONFIG_FILE: &str = "config.json";
const CONFIG_DEF_FILE: &str = "config_default.json";

/// stdout, stderr をリダイレクトし、デーモン化する。
///
/// ファイルオープンに失敗したら exit(1) する。
/// デーモン化に失敗したら exit(1) する。
/// 成功した場合は元の親プロセスは正常終了し、子プロセスが以降の処理を続行する。
fn daemon() {
    let stdout = match File::create(STDOUT_FILE) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Open {} error: {}", STDOUT_FILE, e);
            std::process::exit(1);
        }
    };
    let stderr = match File::create(STDERR_FILE) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Open {} error: {}", STDERR_FILE, e);
            std::process::exit(1);
        }
    };

    let daemonize = Daemonize::new()
        .pid_file(PID_FILE)
        //.chown_pid_file(true)
        .working_directory(".")
        //.user("nobody")
        //.group("daemon")
        .stdout(stdout)
        .stderr(stderr);

    if let Err(e) = daemonize.start() {
        eprintln!("Daemonize error: {}", e);
        std::process::exit(1);
    }
}

/// ロギングシステムを有効化する。
///
/// デーモンならファイルへの書き出しのみ、
/// そうでないならファイルと stdout へ書き出す。
///
/// ログレベルは Error, Warn, Info, Debug, Trace の5段階である。
/// ファイルへは Info 以上、stdout へは Trace 以上のログが出力される。
///
/// * `is_daemon` - デーモンかどうか。
fn init_log(is_daemon: bool) {
    let config = ConfigBuilder::new()
        .set_time_format_custom(format_description!(
            "[year]-[month]-[day] [hour]:[minute]:[second]"
        ))
        .build();
    let file = OpenOptions::new()
        .append(true)
        .create(true)
        .open(LOG_FILE)
        .unwrap();

    // filter = Off, Error, Warn, Info, Debug, Trace
    let loggers: Vec<Box<dyn SharedLogger>> = if is_daemon {
        vec![WriteLogger::new(LevelFilter::Info, config, file)]
    } else {
        vec![
            TermLogger::new(
                LevelFilter::Trace,
                config.clone(),
                TerminalMode::Stdout,
                ColorChoice::Never,
            ),
            WriteLogger::new(LevelFilter::Info, config, file),
        ]
    };
    CombinedLogger::init(loggers).unwrap();
}

/// 設定データをロードする。
fn load_config() -> Result<()> {
    {
        // デフォルト設定ファイルを削除する
        info!("remove {}", CONFIG_DEF_FILE);
        if let Err(e) = remove_file(CONFIG_DEF_FILE) {
            warn!(
                "removing {} failed (the first time execution?): {}",
                CONFIG_DEF_FILE, e
            );
        }
        // デフォルト設定を書き出す
        // 600 でアトミックに必ず新規作成する、失敗したらエラー
        info!("writing default config to {}", CONFIG_DEF_FILE);
        let mut f = OpenOptions::new()
            .write(true)
            .create_new(true)
            .mode(0o600)
            .open(CONFIG_DEF_FILE)
            .with_context(|| format!("Failed to open {}", CONFIG_DEF_FILE))?;
        f.write_all(DEF_CONFIG_JSON.as_bytes())
            .with_context(|| format!("Failed to write {}", CONFIG_DEF_FILE))?;
        info!("OK: written to {}", CONFIG_DEF_FILE);
        // close
    }

    let mut json_str = String::new();
    {
        // 設定ファイルを読む
        // open 後パーミッションを確認し、危険ならエラーとする
        info!("loading config: {}", CONFIG_FILE);
        let mut f = OpenOptions::new()
            .read(true)
            .open(CONFIG_FILE)
            .with_context(|| format!("Failed to open {} (the first execution?)", CONFIG_FILE))
            .with_context(|| {
                format!(
                    "HINT: Copy {} to {} and try again",
                    CONFIG_DEF_FILE, CONFIG_FILE
                )
            })?;

        let metadata = f.metadata()?;
        let permissions = metadata.permissions();
        let masked = permissions.mode() & 0o777;
        ensure!(
            masked == 0o600,
            "Config file permission is not 600: {:03o}",
            permissions.mode()
        );

        f.read_to_string(&mut json_str)
            .with_context(|| format!("Failed to read {}", CONFIG_FILE))?;
        info!("OK: {} loaded", CONFIG_FILE);
        // close
    }

    // json パースして設定システムを初期化
    let json_list = [DEF_CONFIG_JSON, TW_CONTENTS_JSON, &json_str];
    sys::config::init();
    for (i, json_str) in json_list.iter().enumerate() {
        sys::config::add_config(json_str).with_context(|| format!("Config load failed: {}", i))?;
    }

    Ok(())
}

async fn boot_tweet_task(ctrl: Control) -> Result<()> {
    let build_info: &str = &*sys::version::VERSION_INFO;
    // 同一テキストをツイートしようとするとエラーになるので日時を含める
    let now = chrono::Local::now();
    let now = now.format("%F %T %:z");
    let msg = format!("[{}] Boot...\n{}", now, build_info);

    {
        let mut twitter = ctrl.sysmods().twitter.write().await;
        twitter.tweet(&msg).await?;
    }

    Ok(())
}

/// システムメイン処理。
/// コマンドラインとデーモン化、ログの初期化の後に入る。
///
/// 設定データをロードする。
/// その後、システムモジュールとタスクサーバを初期化し、システムの実行を開始する。
fn system_main() -> Result<()> {
    loop {
        info!("system main");
        info!("{}", *sys::version::VERSION_INFO);

        load_config()?;

        let run_result;
        {
            let sysmods = SystemModules::new()?;
            let ts = TaskServer::new(sysmods);

            ts.sysmod_start();
            ts.spawn_oneshot_task("boot_tweet", boot_tweet_task);
            run_result = ts.run();
        }
        info!("task server dropped");

        match run_result {
            RunResult::Shutdown => {
                info!("result: shutdown");
                break;
            }
            RunResult::Reboot => {
                info!("result: reboot");
            }
        }
    }

    Ok(())
}

/// コマンドラインのヘルプを表示する。
///
/// * `program` - プログラム名 (argv\[0\])。
/// * `opts` - パーサオブジェクト。
fn print_help(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

/// エントリポイント。
///
/// コマンドラインとデーモン化、ログの初期化処理をしたのち、[system_main] を呼ぶ。
fn main() -> Result<()> {
    // コマンドライン引数のパース
    let args: Vec<String> = env::args().collect();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print this help");
    opts.optflag("d", "daemon", "Run as daemon");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(fail) => {
            eprintln!("{}", fail);
            std::process::exit(1);
        }
    };

    // --help がある場合は出力して終了
    if matches.opt_present("h") {
        print_help(program, opts);
        std::process::exit(0);
    }

    if matches.opt_present("d") {
        daemon();
        init_log(true);
    } else {
        init_log(false);
    }

    system_main().map_err(|e| {
        error!("Error in system_main");
        e
    })?;
    Ok(())
}
<commit_msg>普通に drop する<commit_after>//! Rust 版管理人形

// TODO: 最終的には外すこと
#![allow(dead_code)]
#![allow(unused_variables)]

mod sys;
mod sysmod;

use anyhow::{ensure, Context, Result};
use daemonize::Daemonize;
use getopts::Options;
use log::{error, info, warn, LevelFilter};
use simplelog::format_description;
use simplelog::{ColorChoice, TerminalMode};
use simplelog::{CombinedLogger, ConfigBuilder, SharedLogger, TermLogger, WriteLogger};
use std::env;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use sys::taskserver::{Control, TaskServer};
use sysmod::SystemModules;

use crate::sys::taskserver::RunResult;

/// デーモン化の際に指定する stdout のリダイレクト先。
const STDOUT_FILE: &str = "stdout.txt";
/// デーモン化の際に指定する stderr のリダイレクト先。
const STDERR_FILE: &str = "stderr.txt";
/// デーモン化の際に指定する pid ファイルパス。
const PID_FILE: &str = "rshanghai.pid";
/// ログのファイル出力先。
const LOG_FILE: &str = "rshanghai.log";

/// デフォルトの設定データ(json source)。
/// [include_str!] でバイナリに含める。
const DEF_CONFIG_JSON: &str = include_str!("res/config_default.json");
const TW_CONTENTS_JSON: &str = include_str!("res/tw_contents.json");
const CONFIG_FILE: &str = "config.json";
const CONFIG_DEF_FILE: &str = "config_default.json";

/// stdout, stderr をリダイレクトし、デーモン化する。
///
/// ファイルオープンに失敗したら exit(1) する。
/// デーモン化に失敗したら exit(1) する。
/// 成功した場合は元の親プロセスは正常終了し、子プロセスが以降の処理を続行する。
fn daemon() {
    let stdout = match File::create(STDOUT_FILE) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Open {} error: {}", STDOUT_FILE, e);
            std::process::exit(1);
        }
    };
    let stderr = match File::create(STDERR_FILE) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Open {} error: {}", STDERR_FILE, e);
            std::process::exit(1);
        }
    };

    let daemonize = Daemonize::new()
        .pid_file(PID_FILE)
        //.chown_pid_file(true)
        .working_directory(".")
        //.user("nobody")
        //.group("daemon")
        .stdout(stdout)
        .stderr(stderr);

    if let Err(e) = daemonize.start() {
        eprintln!("Daemonize error: {}", e);
        std::process::exit(1);
    }
}

/// ロギングシステムを有効化する。
///
/// デーモンならファイルへの書き出しのみ、
/// そうでないならファイルと stdout へ書き出す。
///
/// ログレベルは Error, Warn, Info, Debug, Trace の5段階である。
/// ファイルへは Info 以上、stdout へは Trace 以上のログが出力される。
///
/// * `is_daemon` - デーモンかどうか。
fn init_log(is_daemon: bool) {
    let config = ConfigBuilder::new()
        .set_time_format_custom(format_description!(
            "[year]-[month]-[day] [hour]:[minute]:[second]"
        ))
        .build();
    let file = OpenOptions::new()
        .append(true)
        .create(true)
        .open(LOG_FILE)
        .unwrap();

    // filter = Off, Error, Warn, Info, Debug, Trace
    let loggers: Vec<Box<dyn SharedLogger>> = if is_daemon {
        vec![WriteLogger::new(LevelFilter::Info, config, file)]
    } else {
        vec![
            TermLogger::new(
                LevelFilter::Trace,
                config.clone(),
                TerminalMode::Stdout,
                ColorChoice::Never,
            ),
            WriteLogger::new(LevelFilter::Info, config, file),
        ]
    };
    CombinedLogger::init(loggers).unwrap();
}

/// 設定データをロードする。
fn load_config() -> Result<()> {
    {
        // デフォルト設定ファイルを削除する
        info!("remove {}", CONFIG_DEF_FILE);
        if let Err(e) = remove_file(CONFIG_DEF_FILE) {
            warn!(
                "removing {} failed (the first time execution?): {}",
                CONFIG_DEF_FILE, e
            );
        }
        // デフォルト設定を書き出す
        // 600 でアトミックに必ず新規作成する、失敗したらエラー
        info!("writing default config to {}", CONFIG_DEF_FILE);
        let mut f = OpenOptions::new()
            .write(true)
            .create_new(true)
            .mode(0o600)
            .open(CONFIG_DEF_FILE)
            .with_context(|| format!("Failed to open {}", CONFIG_DEF_FILE))?;
        f.write_all(DEF_CONFIG_JSON.as_bytes())
            .with_context(|| format!("Failed to write {}", CONFIG_DEF_FILE))?;
        info!("OK: written to {}", CONFIG_DEF_FILE);
        // close
    }

    let mut json_str = String::new();
    {
        // 設定ファイルを読む
        // open 後パーミッションを確認し、危険ならエラーとする
        info!("loading config: {}", CONFIG_FILE);
        let mut f = OpenOptions::new()
            .read(true)
            .open(CONFIG_FILE)
            .with_context(|| format!("Failed to open {} (the first execution?)", CONFIG_FILE))
            .with_context(|| {
                format!(
                    "HINT: Copy {} to {} and try again",
                    CONFIG_DEF_FILE, CONFIG_FILE
                )
            })?;

        let metadata = f.metadata()?;
        let permissions = metadata.permissions();
        let masked = permissions.mode() & 0o777;
        ensure!(
            masked == 0o600,
            "Config file permission is not 600: {:03o}",
            permissions.mode()
        );

        f.read_to_string(&mut json_str)
            .with_context(|| format!("Failed to read {}", CONFIG_FILE))?;
        info!("OK: {} loaded", CONFIG_FILE);
        // close
    }

    // json パースして設定システムを初期化
    let json_list = [DEF_CONFIG_JSON, TW_CONTENTS_JSON, &json_str];
    sys::config::init();
    for (i, json_str) in json_list.iter().enumerate() {
        sys::config::add_config(json_str).with_context(|| format!("Config load failed: {}", i))?;
    }

    Ok(())
}

async fn boot_tweet_task(ctrl: Control) -> Result<()> {
    let build_info: &str = &*sys::version::VERSION_INFO;
    // 同一テキストをツイートしようとするとエラーになるので日時を含める
    let now = chrono::Local::now();
    let now = now.format("%F %T %:z");
    let msg = format!("[{}] Boot...\n{}", now, build_info);

    {
        let mut twitter = ctrl.sysmods().twitter.write().await;
        twitter.tweet(&msg).await?;
    }

    Ok(())
}

/// システムメイン処理。
/// コマンドラインとデーモン化、ログの初期化の後に入る。
///
/// 設定データをロードする。
/// その後、システムモジュールとタスクサーバを初期化し、システムの実行を開始する。
fn system_main() -> Result<()> {
    loop {
        info!("system main");
        info!("{}", *sys::version::VERSION_INFO);

        load_config()?;

        let sysmods = SystemModules::new()?;
        let ts = TaskServer::new(sysmods);

        ts.sysmod_start();
        ts.spawn_oneshot_task("boot_tweet", boot_tweet_task);
        let run_result = ts.run();

        drop(ts);
        info!("task server dropped");

        match run_result {
            RunResult::Shutdown => {
                info!("result: shutdown");
                break;
            }
            RunResult::Reboot => {
                info!("result: reboot");
            }
        }
    }

    Ok(())
}

/// コマンドラインのヘルプを表示する。
///
/// * `program` - プログラム名 (argv\[0\])。
/// * `opts` - パーサオブジェクト。
fn print_help(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

/// エントリポイント。
///
/// コマンドラインとデーモン化、ログの初期化処理をしたのち、[system_main] を呼ぶ。
fn main() -> Result<()> {
    // コマンドライン引数のパース
    let args: Vec<String> = env::args().collect();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print this help");
    opts.optflag("d", "daemon", "Run as daemon");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(fail) => {
            eprintln!("{}", fail);
            std::process::exit(1);
        }
    };

    // --help がある場合は出力して終了
    if matches.opt_present("h") {
        print_help(program, opts);
        std::process::exit(0);
    }

    if matches.opt_present("d") {
        daemon();
        init_log(true);
    } else {
        init_log(false);
    }

    system_main().map_err(|e| {
        error!("Error in system_main");
        e
    })?;
    Ok(())
}
<|endoftext|>