<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This module contains the public APIs supported by the bytecode verifier.
use crate::binary_views::BinaryIndexedView;
use diem_types::vm_status::StatusCode;
use move_core_types::{identifier::Identifier, language_storage::ModuleId};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use vm::{
    access::{ModuleAccess, ScriptAccess},
    errors::{verification_error, Location, PartialVMError, PartialVMResult, VMResult},
    file_format::{
        CompiledModule, CompiledScript, FunctionHandle, FunctionHandleIndex, ModuleHandle,
        ModuleHandleIndex, SignatureToken, StructHandle, StructHandleIndex, TableIndex,
    },
    IndexKind,
};

pub struct DependencyChecker<'a> {
    resolver: BinaryIndexedView<'a>,
    // (Module -> CompiledModule) for (at least) all immediate dependencies
    dependency_map: BTreeMap<ModuleId, &'a CompiledModule>,
    // (Module::StructName -> handle) for all types of all dependencies
    struct_id_to_handle_map: HashMap<(ModuleId, Identifier), StructHandleIndex>,
    // (Module::FunctionName -> handle) for all public functions of all dependencies
    func_id_to_handle_map: HashMap<(ModuleId, Identifier), FunctionHandleIndex>,
}

impl<'a> DependencyChecker<'a> {
    pub fn verify_module(
        module: &'a CompiledModule,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> VMResult<()> {
        Self::verify_module_impl(module, dependencies)
            .map_err(|e| e.finish(Location::Module(module.self_id())))
    }

    fn verify_module_impl(
        module: &'a CompiledModule,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> PartialVMResult<()> {
        let module_id = module.self_id();
        let mut dependency_map = BTreeMap::new();
        for dependency in dependencies {
            let dependency_id = dependency.self_id();
            if module_id != dependency_id {
                dependency_map.insert(dependency_id, dependency);
            }
        }

        let mut checker = Self {
            resolver: BinaryIndexedView::Module(module),
            dependency_map,
            struct_id_to_handle_map: HashMap::new(),
            func_id_to_handle_map: HashMap::new(),
        };
        checker.build_deps_entry_point();

        // verify dependencies
        checker.verify_imported_modules(module.module_handles(), Some(module.self_handle_idx()))?;
        checker.verify_imported_structs(module.struct_handles(), Some(module.self_handle_idx()))?;
        checker.verify_imported_functions(module.function_handles(), Some(module.self_handle_idx()))
    }

    pub fn verify_script(
        script: &'a CompiledScript,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> VMResult<()> {
        Self::verify_script_impl(script, dependencies).map_err(|e| e.finish(Location::Script))
    }

    pub fn verify_script_impl(
        script: &'a CompiledScript,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> PartialVMResult<()> {
        let mut dependency_map = BTreeMap::new();
        for dependency in dependencies {
            let dependency_id = dependency.self_id();
            dependency_map.insert(dependency_id, dependency);
        }
        let mut checker = Self {
            resolver: BinaryIndexedView::Script(script),
            dependency_map,
            struct_id_to_handle_map: HashMap::new(),
            func_id_to_handle_map: HashMap::new(),
        };
        checker.build_deps_entry_point();

        checker.verify_imported_modules(script.module_handles(), None)?;
        checker.verify_imported_structs(script.struct_handles(), None)?;
        checker.verify_imported_functions(script.function_handles(), None)
    }

    fn build_deps_entry_point(&mut self) {
        for (module_id, module) in &self.dependency_map {
            // Module::StructName -> def handle idx
            for struct_def in module.struct_defs() {
                let struct_handle = module.struct_handle_at(struct_def.struct_handle);
                let struct_name = module.identifier_at(struct_handle.name);
                self.struct_id_to_handle_map.insert(
                    (module_id.clone(), struct_name.to_owned()),
                    struct_def.struct_handle,
                );
            }
            // Module::FuncName -> def handle idx
            for func_def in module.function_defs() {
                if !func_def.is_public {
                    continue;
                }
                let func_handle = module.function_handle_at(func_def.function);
                let func_name = module.identifier_at(func_handle.name);
                self.func_id_to_handle_map
                    .insert((module_id.clone(), func_name.to_owned()), func_def.function);
            }
        }
    }

    fn verify_imported_modules(
        &self,
        module_handles: &[ModuleHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, module_handle) in module_handles.iter().enumerate() {
            let module_id = self.resolver.module_id_for_handle(module_handle);
            if Some(ModuleHandleIndex(idx as u16)) != self_module
                && !self.dependency_map.contains_key(&module_id)
            {
                return Err(verification_error(
                    StatusCode::MISSING_DEPENDENCY,
                    IndexKind::ModuleHandle,
                    idx as TableIndex,
                ));
            }
        }
        Ok(())
    }

    fn verify_imported_structs(
        &self,
        struct_handles: &[StructHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, struct_handle) in struct_handles.iter().enumerate() {
            if Some(struct_handle.module) == self_module {
                continue;
            }
            let owner_module_id = self
                .resolver
                .module_id_for_handle(self.resolver.module_handle_at(struct_handle.module));
            // TODO: remove unwrap
            let owner_module = self.dependency_map.get(&owner_module_id).unwrap();
            let struct_name = self.resolver.identifier_at(struct_handle.name);
            match self
                .struct_id_to_handle_map
                .get(&(owner_module_id, struct_name.to_owned()))
            {
                Some(def_idx) => {
                    let def_handle = owner_module.struct_handle_at(*def_idx);
                    if struct_handle.is_nominal_resource != def_handle.is_nominal_resource
                        || struct_handle.type_parameters != def_handle.type_parameters
                    {
                        return Err(verification_error(
                            StatusCode::TYPE_MISMATCH,
                            IndexKind::StructHandle,
                            idx as TableIndex,
                        ));
                    }
                }
                None => {
                    return Err(verification_error(
                        StatusCode::LOOKUP_FAILED,
                        IndexKind::StructHandle,
                        idx as TableIndex,
                    ))
                }
            }
        }
        Ok(())
    }

    fn verify_imported_functions(
        &self,
        function_handles: &[FunctionHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, function_handle) in function_handles.iter().enumerate() {
            if Some(function_handle.module) == self_module {
                continue;
            }
            let owner_module_id = self
                .resolver
                .module_id_for_handle(self.resolver.module_handle_at(function_handle.module));
            let function_name = self.resolver.identifier_at(function_handle.name);
            // TODO: remove unwrap
            let owner_module = self.dependency_map.get(&owner_module_id).unwrap();
            match self
                .func_id_to_handle_map
                .get(&(owner_module_id.clone(), function_name.to_owned()))
            {
                Some(def_idx) => {
                    let def_handle = owner_module.function_handle_at(*def_idx);
                    // same type parameter constraints
                    if function_handle.type_parameters != def_handle.type_parameters {
                        return Err(verification_error(
                            StatusCode::TYPE_MISMATCH,
                            IndexKind::FunctionHandle,
                            idx as TableIndex,
                        ));
                    }
                    // same parameters
                    let handle_params = self.resolver.signature_at(function_handle.parameters);
                    let def_params = match self.dependency_map.get(&owner_module_id) {
                        Some(module) => module.signature_at(def_handle.parameters),
                        None => {
                            return Err(verification_error(
                                StatusCode::LOOKUP_FAILED,
                                IndexKind::FunctionHandle,
                                idx as TableIndex,
                            ))
                        }
                    };
                    self.compare_cross_module_signatures(
                        &handle_params.0,
                        &def_params.0,
                        owner_module,
                    )
                    .map_err(|e| e.at_index(IndexKind::FunctionHandle, idx as TableIndex))?;

                    // same return_
                    let handle_return = self.resolver.signature_at(function_handle.return_);
                    let def_return = match self.dependency_map.get(&owner_module_id) {
                        Some(module) => module.signature_at(def_handle.return_),
                        None => {
                            return Err(verification_error(
                                StatusCode::LOOKUP_FAILED,
                                IndexKind::FunctionHandle,
                                idx as TableIndex,
                            ))
                        }
                    };
                    self.compare_cross_module_signatures(
                        &handle_return.0,
                        &def_return.0,
                        owner_module,
                    )
                    .map_err(|e| e.at_index(IndexKind::FunctionHandle, idx as TableIndex))?;
                }
                None => {
                    return Err(verification_error(
                        StatusCode::LOOKUP_FAILED,
                        IndexKind::FunctionHandle,
                        idx as TableIndex,
                    ));
                }
            }
        }
        Ok(())
    }

    pub fn compare_cross_module_signatures(
        &self,
        handle_sig: &[SignatureToken],
        def_sig: &[SignatureToken],
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        if handle_sig.len() != def_sig.len() {
            return Err(PartialVMError::new(StatusCode::TYPE_MISMATCH));
        }
        for (handle_type, def_type) in handle_sig.iter().zip(def_sig) {
            self.compare_types(handle_type, def_type, def_module)?;
        }
        Ok(())
    }

    fn compare_types(
        &self,
        handle_type: &SignatureToken,
        def_type: &SignatureToken,
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        match (handle_type, def_type) {
            (SignatureToken::Bool, SignatureToken::Bool)
            | (SignatureToken::U8, SignatureToken::U8)
            | (SignatureToken::U64, SignatureToken::U64)
            | (SignatureToken::U128, SignatureToken::U128)
            | (SignatureToken::Address, SignatureToken::Address)
            | (SignatureToken::Signer, SignatureToken::Signer) => Ok(()),
            (SignatureToken::Vector(ty1), SignatureToken::Vector(ty2)) => {
                self.compare_types(ty1, ty2, def_module)
            }
            (SignatureToken::Struct(idx1), SignatureToken::Struct(idx2)) => {
                self.compare_structs(*idx1, *idx2, def_module)
            }
            (
                SignatureToken::StructInstantiation(idx1, inst1),
                SignatureToken::StructInstantiation(idx2, inst2),
            ) => {
                self.compare_structs(*idx1, *idx2, def_module)?;
                self.compare_cross_module_signatures(inst1, inst2, def_module)
            }
            (SignatureToken::Reference(ty1), SignatureToken::Reference(ty2))
            | (SignatureToken::MutableReference(ty1), SignatureToken::MutableReference(ty2)) => {
                self.compare_types(ty1, ty2, def_module)
            }
            (SignatureToken::TypeParameter(idx1), SignatureToken::TypeParameter(idx2)) => {
                if idx1 != idx2 {
                    Err(PartialVMError::new(StatusCode::TYPE_MISMATCH))
                } else {
                    Ok(())
                }
            }
            _ => Err(PartialVMError::new(StatusCode::TYPE_MISMATCH)),
        }
    }

    fn compare_structs(
        &self,
        idx1: StructHandleIndex,
        idx2: StructHandleIndex,
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        // grab ModuleId and struct name for the module being verified
        let struct_handle = self.resolver.struct_handle_at(idx1);
        let module_handle = self.resolver.module_handle_at(struct_handle.module);
        let module_id = self.resolver.module_id_for_handle(module_handle);
        let struct_name = self.resolver.identifier_at(struct_handle.name);

        // grab ModuleId and struct name for the definition
        let def_struct_handle = def_module.struct_handle_at(idx2);
        let def_module_handle = def_module.module_handle_at(def_struct_handle.module);
        let def_module_id = def_module.module_id_for_handle(def_module_handle);
        let def_struct_name = def_module.identifier_at(def_struct_handle.name);

        if module_id != def_module_id || struct_name != def_struct_name {
            Err(PartialVMError::new(StatusCode::TYPE_MISMATCH))
        } else {
            Ok(())
        }
    }
}

pub struct CyclicModuleDependencyChecker {}

impl CyclicModuleDependencyChecker {
    pub fn verify_module<F: Fn(&ModuleId) -> Vec<ModuleId>>(
        module: &CompiledModule,
        immediate_module_dependencies: F,
    ) -> VMResult<()> {
        Self::verify_module_impl(module, immediate_module_dependencies)
            .map_err(|e| e.finish(Location::Module(module.self_id())))
    }

    fn verify_module_impl<F: Fn(&ModuleId) -> Vec<ModuleId>>(
        module: &CompiledModule,
        immediate_module_dependencies: F,
    ) -> PartialVMResult<()> {
        // A variant of the three-color DFS, visit each node at max once
        fn dfs_visit<F: Fn(&ModuleId) -> Vec<ModuleId>>(
            cursor_module: ModuleId,
            modules_discovered: &mut BTreeSet<ModuleId>,
            modules_finished: &mut BTreeSet<ModuleId>,
            immediate_module_dependencies: &F,
        ) -> bool {
            modules_discovered.insert(cursor_module.clone());
            for next_module in immediate_module_dependencies(&cursor_module) {
                if modules_discovered.contains(&next_module) {
                    return true;
                }
                if !modules_finished.contains(&next_module)
                    && dfs_visit(
                        next_module,
                        modules_discovered,
                        modules_finished,
                        immediate_module_dependencies,
                    )
                {
                    return true;
                }
            }
            modules_discovered.remove(&cursor_module);
            modules_finished.insert(cursor_module);
            false
        }

        let mut modules_discovered = BTreeSet::new();
        let mut modules_finished = BTreeSet::new();

        modules_discovered.insert(module.self_id());
        for dep in module.immediate_module_dependencies() {
            if dfs_visit(
                dep,
                &mut modules_discovered,
                &mut modules_finished,
                &immediate_module_dependencies,
            ) {
                return Err(PartialVMError::new(StatusCode::CYCLIC_MODULE_DEPENDENCY));
            }
        }

        Ok(())
    }
}
<commit_msg>[bytecode-verifier] explain and simplify the cyclic dep check algorithm<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This module contains the public APIs supported by the bytecode verifier.
use crate::binary_views::BinaryIndexedView;
use diem_types::vm_status::StatusCode;
use move_core_types::{identifier::Identifier, language_storage::ModuleId};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use vm::{
    access::{ModuleAccess, ScriptAccess},
    errors::{verification_error, Location, PartialVMError, PartialVMResult, VMResult},
    file_format::{
        CompiledModule, CompiledScript, FunctionHandle, FunctionHandleIndex, ModuleHandle,
        ModuleHandleIndex, SignatureToken, StructHandle, StructHandleIndex, TableIndex,
    },
    IndexKind,
};

pub struct DependencyChecker<'a> {
    resolver: BinaryIndexedView<'a>,
    // (Module -> CompiledModule) for (at least) all immediate dependencies
    dependency_map: BTreeMap<ModuleId, &'a CompiledModule>,
    // (Module::StructName -> handle) for all types of all dependencies
    struct_id_to_handle_map: HashMap<(ModuleId, Identifier), StructHandleIndex>,
    // (Module::FunctionName -> handle) for all public functions of all dependencies
    func_id_to_handle_map: HashMap<(ModuleId, Identifier), FunctionHandleIndex>,
}

impl<'a> DependencyChecker<'a> {
    pub fn verify_module(
        module: &'a CompiledModule,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> VMResult<()> {
        Self::verify_module_impl(module, dependencies)
            .map_err(|e| e.finish(Location::Module(module.self_id())))
    }

    fn verify_module_impl(
        module: &'a CompiledModule,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> PartialVMResult<()> {
        let module_id = module.self_id();
        let mut dependency_map = BTreeMap::new();
        for dependency in dependencies {
            let dependency_id = dependency.self_id();
            if module_id != dependency_id {
                dependency_map.insert(dependency_id, dependency);
            }
        }

        let mut checker = Self {
            resolver: BinaryIndexedView::Module(module),
            dependency_map,
            struct_id_to_handle_map: HashMap::new(),
            func_id_to_handle_map: HashMap::new(),
        };
        checker.build_deps_entry_point();

        // verify dependencies
        checker.verify_imported_modules(module.module_handles(), Some(module.self_handle_idx()))?;
        checker.verify_imported_structs(module.struct_handles(), Some(module.self_handle_idx()))?;
        checker.verify_imported_functions(module.function_handles(), Some(module.self_handle_idx()))
    }

    pub fn verify_script(
        script: &'a CompiledScript,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> VMResult<()> {
        Self::verify_script_impl(script, dependencies).map_err(|e| e.finish(Location::Script))
    }

    pub fn verify_script_impl(
        script: &'a CompiledScript,
        dependencies: impl IntoIterator<Item = &'a CompiledModule>,
    ) -> PartialVMResult<()> {
        let mut dependency_map = BTreeMap::new();
        for dependency in dependencies {
            let dependency_id = dependency.self_id();
            dependency_map.insert(dependency_id, dependency);
        }
        let mut checker = Self {
            resolver: BinaryIndexedView::Script(script),
            dependency_map,
            struct_id_to_handle_map: HashMap::new(),
            func_id_to_handle_map: HashMap::new(),
        };
        checker.build_deps_entry_point();

        checker.verify_imported_modules(script.module_handles(), None)?;
        checker.verify_imported_structs(script.struct_handles(), None)?;
        checker.verify_imported_functions(script.function_handles(), None)
    }

    fn build_deps_entry_point(&mut self) {
        for (module_id, module) in &self.dependency_map {
            // Module::StructName -> def handle idx
            for struct_def in module.struct_defs() {
                let struct_handle = module.struct_handle_at(struct_def.struct_handle);
                let struct_name = module.identifier_at(struct_handle.name);
                self.struct_id_to_handle_map.insert(
                    (module_id.clone(), struct_name.to_owned()),
                    struct_def.struct_handle,
                );
            }
            // Module::FuncName -> def handle idx
            for func_def in module.function_defs() {
                if !func_def.is_public {
                    continue;
                }
                let func_handle = module.function_handle_at(func_def.function);
                let func_name = module.identifier_at(func_handle.name);
                self.func_id_to_handle_map
                    .insert((module_id.clone(), func_name.to_owned()), func_def.function);
            }
        }
    }

    fn verify_imported_modules(
        &self,
        module_handles: &[ModuleHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, module_handle) in module_handles.iter().enumerate() {
            let module_id = self.resolver.module_id_for_handle(module_handle);
            if Some(ModuleHandleIndex(idx as u16)) != self_module
                && !self.dependency_map.contains_key(&module_id)
            {
                return Err(verification_error(
                    StatusCode::MISSING_DEPENDENCY,
                    IndexKind::ModuleHandle,
                    idx as TableIndex,
                ));
            }
        }
        Ok(())
    }

    fn verify_imported_structs(
        &self,
        struct_handles: &[StructHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, struct_handle) in struct_handles.iter().enumerate() {
            if Some(struct_handle.module) == self_module {
                continue;
            }
            let owner_module_id = self
                .resolver
                .module_id_for_handle(self.resolver.module_handle_at(struct_handle.module));
            // TODO: remove unwrap
            let owner_module = self.dependency_map.get(&owner_module_id).unwrap();
            let struct_name = self.resolver.identifier_at(struct_handle.name);
            match self
                .struct_id_to_handle_map
                .get(&(owner_module_id, struct_name.to_owned()))
            {
                Some(def_idx) => {
                    let def_handle = owner_module.struct_handle_at(*def_idx);
                    if struct_handle.is_nominal_resource != def_handle.is_nominal_resource
                        || struct_handle.type_parameters != def_handle.type_parameters
                    {
                        return Err(verification_error(
                            StatusCode::TYPE_MISMATCH,
                            IndexKind::StructHandle,
                            idx as TableIndex,
                        ));
                    }
                }
                None => {
                    return Err(verification_error(
                        StatusCode::LOOKUP_FAILED,
                        IndexKind::StructHandle,
                        idx as TableIndex,
                    ))
                }
            }
        }
        Ok(())
    }

    fn verify_imported_functions(
        &self,
        function_handles: &[FunctionHandle],
        self_module: Option<ModuleHandleIndex>,
    ) -> PartialVMResult<()> {
        for (idx, function_handle) in function_handles.iter().enumerate() {
            if Some(function_handle.module) == self_module {
                continue;
            }
            let owner_module_id = self
                .resolver
                .module_id_for_handle(self.resolver.module_handle_at(function_handle.module));
            let function_name = self.resolver.identifier_at(function_handle.name);
            // TODO: remove unwrap
            let owner_module = self.dependency_map.get(&owner_module_id).unwrap();
            match self
                .func_id_to_handle_map
                .get(&(owner_module_id.clone(), function_name.to_owned()))
            {
                Some(def_idx) => {
                    let def_handle = owner_module.function_handle_at(*def_idx);
                    // same type parameter constraints
                    if function_handle.type_parameters != def_handle.type_parameters {
                        return Err(verification_error(
                            StatusCode::TYPE_MISMATCH,
                            IndexKind::FunctionHandle,
                            idx as TableIndex,
                        ));
                    }
                    // same parameters
                    let handle_params = self.resolver.signature_at(function_handle.parameters);
                    let def_params = match self.dependency_map.get(&owner_module_id) {
                        Some(module) => module.signature_at(def_handle.parameters),
                        None => {
                            return Err(verification_error(
                                StatusCode::LOOKUP_FAILED,
                                IndexKind::FunctionHandle,
                                idx as TableIndex,
                            ))
                        }
                    };
                    self.compare_cross_module_signatures(
                        &handle_params.0,
                        &def_params.0,
                        owner_module,
                    )
                    .map_err(|e| e.at_index(IndexKind::FunctionHandle, idx as TableIndex))?;

                    // same return_
                    let handle_return = self.resolver.signature_at(function_handle.return_);
                    let def_return = match self.dependency_map.get(&owner_module_id) {
                        Some(module) => module.signature_at(def_handle.return_),
                        None => {
                            return Err(verification_error(
                                StatusCode::LOOKUP_FAILED,
                                IndexKind::FunctionHandle,
                                idx as TableIndex,
                            ))
                        }
                    };
                    self.compare_cross_module_signatures(
                        &handle_return.0,
                        &def_return.0,
                        owner_module,
                    )
                    .map_err(|e| e.at_index(IndexKind::FunctionHandle, idx as TableIndex))?;
                }
                None => {
                    return Err(verification_error(
                        StatusCode::LOOKUP_FAILED,
                        IndexKind::FunctionHandle,
                        idx as TableIndex,
                    ));
                }
            }
        }
        Ok(())
    }

    pub fn compare_cross_module_signatures(
        &self,
        handle_sig: &[SignatureToken],
        def_sig: &[SignatureToken],
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        if handle_sig.len() != def_sig.len() {
            return Err(PartialVMError::new(StatusCode::TYPE_MISMATCH));
        }
        for (handle_type, def_type) in handle_sig.iter().zip(def_sig) {
            self.compare_types(handle_type, def_type, def_module)?;
        }
        Ok(())
    }

    fn compare_types(
        &self,
        handle_type: &SignatureToken,
        def_type: &SignatureToken,
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        match (handle_type, def_type) {
            (SignatureToken::Bool, SignatureToken::Bool)
            | (SignatureToken::U8, SignatureToken::U8)
            | (SignatureToken::U64, SignatureToken::U64)
            | (SignatureToken::U128, SignatureToken::U128)
            | (SignatureToken::Address, SignatureToken::Address)
            | (SignatureToken::Signer, SignatureToken::Signer) => Ok(()),
            (SignatureToken::Vector(ty1), SignatureToken::Vector(ty2)) => {
                self.compare_types(ty1, ty2, def_module)
            }
            (SignatureToken::Struct(idx1), SignatureToken::Struct(idx2)) => {
                self.compare_structs(*idx1, *idx2, def_module)
            }
            (
                SignatureToken::StructInstantiation(idx1, inst1),
                SignatureToken::StructInstantiation(idx2, inst2),
            ) => {
                self.compare_structs(*idx1, *idx2, def_module)?;
                self.compare_cross_module_signatures(inst1, inst2, def_module)
            }
            (SignatureToken::Reference(ty1), SignatureToken::Reference(ty2))
            | (SignatureToken::MutableReference(ty1), SignatureToken::MutableReference(ty2)) => {
                self.compare_types(ty1, ty2, def_module)
            }
            (SignatureToken::TypeParameter(idx1), SignatureToken::TypeParameter(idx2)) => {
                if idx1 != idx2 {
                    Err(PartialVMError::new(StatusCode::TYPE_MISMATCH))
                } else {
                    Ok(())
                }
            }
            _ => Err(PartialVMError::new(StatusCode::TYPE_MISMATCH)),
        }
    }

    fn compare_structs(
        &self,
        idx1: StructHandleIndex,
        idx2: StructHandleIndex,
        def_module: &CompiledModule,
    ) -> PartialVMResult<()> {
        // grab ModuleId and struct name for the module being verified
        let struct_handle = self.resolver.struct_handle_at(idx1);
        let module_handle = self.resolver.module_handle_at(struct_handle.module);
        let module_id = self.resolver.module_id_for_handle(module_handle);
        let struct_name = self.resolver.identifier_at(struct_handle.name);

        // grab ModuleId and struct name for the definition
        let def_struct_handle = def_module.struct_handle_at(idx2);
        let def_module_handle = def_module.module_handle_at(def_struct_handle.module);
        let def_module_id = def_module.module_id_for_handle(def_module_handle);
        let def_struct_name = def_module.identifier_at(def_struct_handle.name);

        if module_id != def_module_id || struct_name != def_struct_name {
            Err(PartialVMError::new(StatusCode::TYPE_MISMATCH))
        } else {
            Ok(())
        }
    }
}

pub struct CyclicModuleDependencyChecker {}

impl CyclicModuleDependencyChecker {
    pub fn verify_module<F: Fn(&ModuleId) -> Vec<ModuleId>>(
        module: &CompiledModule,
        immediate_module_dependencies: F,
    ) -> VMResult<()> {
        Self::verify_module_impl(module, immediate_module_dependencies)
            .map_err(|e| e.finish(Location::Module(module.self_id())))
    }

    fn verify_module_impl<F: Fn(&ModuleId) -> Vec<ModuleId>>(
        module: &CompiledModule,
        immediate_module_dependencies: F,
    ) -> PartialVMResult<()> {
        // A variant of the three-color DFS, visit each node at max once.
        // This function returns true if a back-edge is found during the DFS.
        fn dfs_visit<F: Fn(&ModuleId) -> Vec<ModuleId>>(
            cursor_module: ModuleId,
            modules_discovered: &mut BTreeSet<ModuleId>,
            modules_finished: &mut BTreeSet<ModuleId>,
            immediate_module_dependencies: &F,
        ) -> bool {
            modules_discovered.insert(cursor_module.clone());
            for next_module in immediate_module_dependencies(&cursor_module) {
                if modules_finished.contains(&next_module) {
                    continue;
                }
                if modules_discovered.contains(&next_module)
                    || dfs_visit(
                        next_module,
                        modules_discovered,
                        modules_finished,
                        immediate_module_dependencies,
                    )
                {
                    return true;
                }
            }
            modules_discovered.remove(&cursor_module);
            modules_finished.insert(cursor_module);
            false
        }

        let mut modules_discovered = BTreeSet::new();
        let mut modules_finished = BTreeSet::new();

        modules_discovered.insert(module.self_id());
        for dep in module.immediate_module_dependencies() {
            if modules_discovered.contains(&dep)
                || dfs_visit(
                    dep,
                    &mut modules_discovered,
                    &mut modules_finished,
                    &immediate_module_dependencies,
                )
            {
                return Err(PartialVMError::new(StatusCode::CYCLIC_MODULE_DEPENDENCY));
            }
        }

        // NOTE: we cannot start `dfs_visit` from `module.self_id()`, instead, we have to run DFS
        // over each of `module.immediate_module_dependencies()`. The reason is: it is possible that
        // `immediate_module_dependencies(&module.self_id()) != module.immediate_module_dependencies()`
        // (note these are two functions). The LHS returns what the loader has in cache, and the
        // cache is accurate for every module EXCEPT for the module that is going to be republished,
        // i.e., the module under cyclic dependency checking. More importantly, the loader may not
        // even have `module` in cache (if we are publishing a new module), on that case, the LHS
        // will abort. But loader will always have the dependencies of this module in cache,
        // regardless of whether this module is a new one or to be updated.

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


<commit_before>use common::{R};
use lapack;
use lapack::lapack_int;
use dense_matrix::DenseMatrix;
use monomial::{Monomial};
use polynomial::{PolyBorrowingMons, PolyOwning};
use mesh::{Mesh, FENum, OShape, SideFace};
use wg_basis::{WGBasis};

use std::num;
use std::vec;

/** Method of Projection onto a Subspace
 * -------------------------------------
 * <Proj(g), e_i> = <g, e_i> for all basis elements e_i in the subspace.
 * Since Proj(g) = sum_j{ a_j e_j } for some a_j's, this gives us a linear system
 *   sum_j { <e_j, e_i> a_j } = <g, e_i>
 * which we solve for the a_j.
 */

pub struct Projector<'self,Mon,MeshT> {

  basis: &'self WGBasis<Mon,MeshT>,

  // Work matrices for lapack to avoid allocations and because lapack enjoys writing over its inputs.
  lapack_ips_int_mons: DenseMatrix,
  lapack_ips_side_mons: DenseMatrix,
  lapack_pivots: ~[lapack_int],
  lapack_pivots_buf: *mut lapack_int,
  lapack_int_proj_rhs: DenseMatrix,
  lapack_side_proj_rhs: DenseMatrix,
}

impl <'self,Mon:Monomial,MeshT:Mesh<Mon>> Projector<'self,Mon,MeshT> {

  pub fn new(basis: &'self WGBasis<Mon,MeshT>) -> Projector<'self,Mon,MeshT> {
    Projector::with_rhs_cols_capacity(basis, 1000u)
  }

  pub fn with_rhs_cols_capacity(basis: &'self WGBasis<Mon,MeshT>, init_rhs_cols_capacity: uint) -> Projector<'self,Mon,MeshT> {
    let (num_int_mons, num_side_mons) = (basis.mons_per_fe_int(), basis.mons_per_fe_side());
    let lapack_ips_int_mons = DenseMatrix::from_elem(num_int_mons, num_int_mons, 0 as R);
    let lapack_ips_side_mons = DenseMatrix::from_elem(num_side_mons, num_side_mons, 0 as R);
    let mut lapack_pivots = vec::from_elem(num::max(num_int_mons, num_side_mons), 0 as lapack_int);
    let lapack_pivots_buf = vec::raw::to_mut_ptr(lapack_pivots);
    let init_num_rhs_cols = init_rhs_cols_capacity;
    let lapack_int_proj_rhs = DenseMatrix::from_elem(num_int_mons, init_num_rhs_cols, 0 as R);
    let lapack_side_proj_rhs = DenseMatrix::from_elem(num_side_mons, init_num_rhs_cols, 0 as R);

    Projector {
      basis: basis,
      lapack_ips_int_mons: lapack_ips_int_mons,
      lapack_ips_side_mons: lapack_ips_side_mons,
      lapack_pivots: lapack_pivots,
      lapack_pivots_buf: lapack_pivots_buf,
      lapack_int_proj_rhs: lapack_int_proj_rhs,
      lapack_side_proj_rhs: lapack_side_proj_rhs,
    }
  }

  #[inline]
  pub fn basis(&self) -> &'self WGBasis<Mon,MeshT> {
    self.basis
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the interiors of the given finite elements in turn. The monomials of the returned polynomials are
  /// gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[inline(never)]
  pub fn projs_to_span_fes_int_supp_basis_els(&mut self,
         g: |&[R]| -> R, fes: &[FENum], fes_oshape: OShape) -> ~[PolyBorrowingMons<'self,Mon>] {

    let int_mons = self.basis.ref_int_mons();

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_int_mons.fill_upper_triangle_from(self.basis.ips_int_mons_for_oshape(fes_oshape));
        self.lapack_ips_int_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_int_proj_rhs.capacity_cols() >= fes.len() {
          self.lapack_int_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_int_proj_rhs = DenseMatrix::of_size_with_cols_capacity(int_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our interior monomials (rows) on the fes (cols).
        self.lapack_int_proj_rhs.fill_from_fn(|r,c| {
          let mon = int_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_int(|x| g(x), mon, fe)
        });
        self.lapack_int_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, int_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, int_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunks(int_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: int_mons })
      .collect()
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the given side face of the given finite elements in turn. The monomials of the returned polynomials
  /// are gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[inline(never)]
  pub fn projs_to_span_fes_side_supp_basis_els(&mut self,
         g: |&[R]| -> R, fes: &[FENum], fes_oshape: OShape, side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(fes_oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(self.basis.ips_side_mons_for_oshape_side(fes_oshape, side_face));
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols() >= fes.len() {
          self.lapack_side_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_side_proj_rhs = DenseMatrix::of_size_with_cols_capacity(side_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our side monomials (rows) on the fes (cols).
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let mon = side_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_side(|x| g(x), mon, fe, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunks(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

  #[inline(never)]
  pub fn proj_int_mons_to_span_oshape_side_supp_basis_els(&mut self,
     int_mons: &[Mon], oshape: OShape, side_face: SideFace) -> ~[PolyOwning<Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a, consisting of inner products between basis elements supported on the side.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(self.basis.ips_side_mons_for_oshape_side(oshape, side_face));
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per interior monomial to be projected onto the side.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols() >= int_mons.len() {
          self.lapack_side_proj_rhs.set_num_cols(int_mons.len());
        } else {
          self.lapack_side_proj_rhs = DenseMatrix::of_size_with_cols_capacity(side_mons.len(), int_mons.len(), 3*int_mons.len()/2);
        }
        //   - Fill the rhs matrix with inner products between our side monomials (rows) and the interior monomials (cols) to be projected.
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let (int_mon, side_basis_mon) = (int_mons[c].clone(), side_mons[r].clone());
          self.basis.mesh.intg_intrel_mon_x_siderel_mon_on_oshape_side(int_mon, side_basis_mon, oshape, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, int_mons.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * int_mons.len())
    };

    sol_as_col_maj_vec
      .chunks(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyOwning { coefs: proj_coefs.to_owned(), mons: side_mons.to_owned() })
      .collect()
  }

} // impl Projector

<commit_msg>Projection function name changes accidentally ommitted from previous commits and formatting fixups.<commit_after>use common::{R};
use lapack;
use lapack::lapack_int;
use dense_matrix::DenseMatrix;
use monomial::{Monomial};
use polynomial::{PolyBorrowingMons, PolyOwning};
use mesh::{Mesh, FENum, OShape, SideFace};
use wg_basis::{WGBasis};

use std::num;
use std::vec;

/** Method of Projection onto a Subspace
 * -------------------------------------
 * <Proj(g), e_i> = <g, e_i> for all basis elements e_i in the subspace.
 * Since Proj(g) = sum_j{ a_j e_j } for some a_j's, this gives us a linear system
 *   sum_j { <e_j, e_i> a_j } = <g, e_i>
 * which we solve for the a_j.
 */

pub struct Projector<'self,Mon,MeshT> {

  basis: &'self WGBasis<Mon,MeshT>,

  // Work matrices for lapack to avoid allocations and because lapack enjoys writing over its inputs.
  lapack_ips_int_mons: DenseMatrix,
  lapack_ips_side_mons: DenseMatrix,
  lapack_pivots: ~[lapack_int],
  lapack_pivots_buf: *mut lapack_int,
  lapack_int_proj_rhs: DenseMatrix,
  lapack_side_proj_rhs: DenseMatrix,
}

impl <'self,Mon:Monomial,MeshT:Mesh<Mon>> Projector<'self,Mon,MeshT> {

  pub fn new(basis: &'self WGBasis<Mon,MeshT>) -> Projector<'self,Mon,MeshT> {
    Projector::with_rhs_cols_capacity(basis, 1000u)
  }

  pub fn with_rhs_cols_capacity(basis: &'self WGBasis<Mon,MeshT>, init_rhs_cols_capacity: uint) -> Projector<'self,Mon,MeshT> {
    let (num_int_mons, num_side_mons) = (basis.mons_per_fe_int(), basis.mons_per_fe_side());
    let lapack_ips_int_mons = DenseMatrix::from_elem(num_int_mons, num_int_mons, 0 as R);
    let lapack_ips_side_mons = DenseMatrix::from_elem(num_side_mons, num_side_mons, 0 as R);
    let mut lapack_pivots = vec::from_elem(num::max(num_int_mons, num_side_mons), 0 as lapack_int);
    let lapack_pivots_buf = vec::raw::to_mut_ptr(lapack_pivots);
    let init_num_rhs_cols = init_rhs_cols_capacity;
    let lapack_int_proj_rhs = DenseMatrix::from_elem(num_int_mons, init_num_rhs_cols, 0 as R);
    let lapack_side_proj_rhs = DenseMatrix::from_elem(num_side_mons, init_num_rhs_cols, 0 as R);

    Projector {
      basis: basis,
      lapack_ips_int_mons: lapack_ips_int_mons,
      lapack_ips_side_mons: lapack_ips_side_mons,
      lapack_pivots: lapack_pivots,
      lapack_pivots_buf: lapack_pivots_buf,
      lapack_int_proj_rhs: lapack_int_proj_rhs,
      lapack_side_proj_rhs: lapack_side_proj_rhs,
    }
  }

  #[inline]
  pub fn basis(&self) -> &'self WGBasis<Mon,MeshT> {
    self.basis
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the interiors of the given finite elements in turn. The monomials of the returned polynomials are
  /// gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[inline(never)]
  pub fn projs_to_int_supp_approx_spaces(&mut self,
                                         g: |&[R]| -> R,
                                         fes: &[FENum],
                                         fes_oshape: OShape) -> ~[PolyBorrowingMons<'self,Mon>] {

    let int_mons = self.basis.ref_int_mons();

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_int_mons.fill_upper_triangle_from(self.basis.ips_int_mons_for_oshape(fes_oshape));
        self.lapack_ips_int_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_int_proj_rhs.capacity_cols() >= fes.len() {
          self.lapack_int_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_int_proj_rhs = DenseMatrix::of_size_with_cols_capacity(int_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our interior monomials (rows) on the fes (cols).
        self.lapack_int_proj_rhs.fill_from_fn(|r,c| {
          let mon = int_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_int(|x| g(x), mon, fe)
        });
        self.lapack_int_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, int_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, int_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunks(int_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: int_mons })
      .collect()
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the given side face of the given finite elements in turn. The monomials of the returned polynomials
  /// are gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[inline(never)]
  pub fn projs_to_side_supp_approx_spaces(&mut self,
                                          g: |&[R]| -> R,
                                          fes: &[FENum],
                                          fes_oshape: OShape,
                                          side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(fes_oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(self.basis.ips_side_mons_for_oshape_side(fes_oshape, side_face));
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols() >= fes.len() {
          self.lapack_side_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_side_proj_rhs = DenseMatrix::of_size_with_cols_capacity(side_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our side monomials (rows) on the fes (cols).
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let mon = side_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_side(|x| g(x), mon, fe, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunks(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

  #[inline(never)]
  pub fn projs_int_mons_to_side_supp_approx_space(&mut self,
                                                  int_mons: &[Mon],
                                                  oshape: OShape,
                                                  side_face: SideFace) -> ~[PolyOwning<Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a, consisting of inner products between basis elements supported on the side.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(self.basis.ips_side_mons_for_oshape_side(oshape, side_face));
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per interior monomial to be projected onto the side.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols() >= int_mons.len() {
          self.lapack_side_proj_rhs.set_num_cols(int_mons.len());
        } else {
          self.lapack_side_proj_rhs = DenseMatrix::of_size_with_cols_capacity(side_mons.len(), int_mons.len(), 3*int_mons.len()/2);
        }
        //   - Fill the rhs matrix with inner products between our side monomials (rows) and the interior monomials (cols) to be projected.
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let (int_mon, side_basis_mon) = (int_mons[c].clone(), side_mons[r].clone());
          self.basis.mesh.intg_intrel_mon_x_siderel_mon_on_oshape_side(int_mon, side_basis_mon, oshape, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, int_mons.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * int_mons.len())
    };

    sol_as_col_maj_vec
      .chunks(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyOwning { coefs: proj_coefs.to_owned(), mons: side_mons.to_owned() })
      .collect()
  }

} // impl Projector

<|endoftext|>


<commit_before>extern mod std;

extern mod crypto {
  fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn MD5(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
}

struct Digest { digest: ~[u8] }

impl Digest {
    fn new(digest: ~[u8]) -> ~Digest { return ~Digest{ digest: digest } }

    fn hexdigest(&self) -> ~str {
        let mut acc = ~"";
        for self.digest.each |&byte| { acc += fmt!("%02x", byte as uint); }
        acc
    }
}

fn hash(data: ~[u8], hash_func: &fn(*u8, libc::c_uint, *u8) -> *u8, len: uint) -> ~Digest {
    Digest::new(
      unsafe {
        vec::from_buf(
          hash_func(
            vec::raw::to_ptr(data),
            data.len() as libc::c_uint, ptr::null()
          ),
          len
        )
      }
    )
}

fn sha1(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA1, 20)
  }
}

fn md5(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::MD5, 16)
  }
}

fn xor_with(subject: &str, val: u8) -> ~[u8] {
  do subject.to_bytes().map |&c| { val ^ c }
}

fn hmac_sha1(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, sha1)
}

fn hmac_md5(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, md5)
}

fn hmac(key: ~str, message: ~str, block_size: uint, hash_func: &fn(~[u8]) -> ~Digest) -> ~Digest {

  let computed_key: &str = match key.len() {
    _ if key.len() > block_size => hash_func(key.to_bytes()).hexdigest(), // TODO this should be .digest more likely
    _ if key.len() < block_size => key + str::from_bytes(vec::from_elem(block_size - key.len(), 0)),
    _ => key
  };

  let o_key_pad = xor_with(computed_key, 0x5c);
  let i_key_pad = xor_with(computed_key, 0x36);
  let bin_message = message.to_bytes();

  hash_func(o_key_pad + hash_func(i_key_pad + bin_message).digest)
}

fn main() {
  if core::os::args().len() < 2 { fail!(~"Nothing to hash: supply an argument") }
  io::println(sha1(core::os::args()[1].clone().to_bytes()).hexdigest());
}

#[test]
fn test_sha1() {
  assert_eq!(sha1("testing SHA1".to_bytes()).hexdigest(), ~"a07bb2f7f56b7b47e54fd9e29b4629c8967dde4c");
}

#[test]
fn test_md5() {
  assert_eq!(md5("testing MD5".to_bytes()).hexdigest(), ~"da35df95d34f166890fa759f5e00e94c");
}

#[test]
fn test_hmac_sha1() {
  assert_eq!(
    hmac_sha1(~"my key", ~"some data to hmac").hexdigest(),
    ~"331c9bf4d7dc8ad7e9bab2f566c8612042a9f4e2"
  )
}

/*
#[test]
fn test_hmac_sha256() {
  assert_eq!(
    hmac(SHA256, ~"my key", ~"some data to hmac"),
    ~"17764a8a2e8c23ae3b9e1781c5ebeb5754c7920806021032e9133051e10118be"
  );
}

#[test]
fn test_hmac_sha512() {
  assert_eq!(
    hmac(SHA512, ~"my key", ~"some data to hmac"),
    ~"b54973feba2e436c4f0911855c80e7320d72edd37b359d6474d714718c52775f163832b79214e9fa9d400208d21372a465b2cda2a1d5ab488bbc02b0daea9626"
  );
}

*/
#[test]
fn test_hmac_md5() {
  assert_eq!(hmac_md5(~"my key", ~"some data to hmac").hexdigest(), ~"befd13e00ee07549520ade402c664a3a");
}
<commit_msg>Support all the other SHA hash methods with their own functions.<commit_after>extern mod std;

extern mod crypto {
  fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn MD5(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA224(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA256(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA384(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA512(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
}

enum HashEngine { MD5, SHA1, SHA224, SHA256, SHA384, SHA512 }

struct Digest { digest: ~[u8] }

impl Digest {
    fn new(digest: ~[u8]) -> ~Digest { return ~Digest{ digest: digest } }

    fn hexdigest(&self) -> ~str {
        let mut acc = ~"";
        for self.digest.each |&byte| { acc += fmt!("%02x", byte as uint); }
        acc
    }
}

fn hash(data: ~[u8], hash_func: &fn(*u8, libc::c_uint, *u8) -> *u8, len: uint) -> ~Digest {
    Digest::new(
      unsafe {
        vec::from_buf(
          hash_func(
            vec::raw::to_ptr(data),
            data.len() as libc::c_uint, ptr::null()
          ),
          len
        )
      }
    )
}

fn sha1(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA1, 20)
  }
}

fn sha224(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA224, 28)
  }
}

fn sha256(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA256, 32)
  }
}

fn sha384(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA384, 48)
  }
}

fn sha512(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::SHA512, 64)
  }
}

fn md5(data: ~[u8]) -> ~Digest {
  unsafe {
    hash(data, crypto::MD5, 16)
  }
}

fn xor_with(subject: &str, val: u8) -> ~[u8] {
  do subject.to_bytes().map |&c| { val ^ c }
}

fn hmac_md5(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, md5)
}

fn hmac_sha1(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, sha1)
}

fn hmac_sha256(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, sha256)
}

fn hmac_sha512(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 128, sha512)
}

fn hmac(key: ~str, message: ~str, block_size: uint, hash_func: &fn(~[u8]) -> ~Digest) -> ~Digest {
  let computed_key: &str = match key.len() {
    _ if key.len() > block_size => hash_func(key.to_bytes()).hexdigest(), // TODO this should be .digest more likely
    _ if key.len() < block_size => key + str::from_bytes(vec::from_elem(block_size - key.len(), 0)),
    _ => key
  };

  let o_key_pad = xor_with(computed_key, 0x5c);
  let i_key_pad = xor_with(computed_key, 0x36);
  let bin_message = message.to_bytes();

  hash_func(o_key_pad + hash_func(i_key_pad + bin_message).digest)
}

fn main() {
  if core::os::args().len() < 2 { fail!(~"Nothing to hash: supply an argument") }
  io::println(sha1(core::os::args()[1].clone().to_bytes()).hexdigest());
}

#[test]
fn test_sha1() {
  assert_eq!(sha1("testing SHA1".to_bytes()).hexdigest(), ~"a07bb2f7f56b7b47e54fd9e29b4629c8967dde4c");
}

#[test]
fn test_md5() {
  assert_eq!(md5("testing MD5".to_bytes()).hexdigest(), ~"da35df95d34f166890fa759f5e00e94c");
}

#[test]
fn test_hmac_sha1() {
  assert_eq!(
    hmac_sha1(~"my key", ~"some data to hmac").hexdigest(),
    ~"331c9bf4d7dc8ad7e9bab2f566c8612042a9f4e2"
  )
}

#[test]
fn test_hmac_sha256() {
  assert_eq!(
    hmac_sha256(~"my key", ~"some data to hmac").hexdigest(),
    ~"17764a8a2e8c23ae3b9e1781c5ebeb5754c7920806021032e9133051e10118be"
  );
}

#[test]
fn test_hmac_sha512() {
  assert_eq!(
    hmac_sha512(~"my key", ~"some data to hmac").hexdigest(),
    ~"b54973feba2e436c4f0911855c80e7320d72edd37b359d6474d714718c52775f163832b79214e9fa9d400208d21372a465b2cda2a1d5ab488bbc02b0daea9626"
  );
}

#[test]
fn test_hmac_md5() {
  assert_eq!(hmac_md5(~"my key", ~"some data to hmac").hexdigest(), ~"befd13e00ee07549520ade402c664a3a");
}
<|endoftext|>


<commit_before>//! A visitor for downcasting arbitrary request (JSON) into a specific type.
use std::{fmt, panic};

use serde::{de::DeserializeOwned, Serialize};

use crate::{
    global_state::{GlobalState, GlobalStateSnapshot},
    lsp_utils::is_canceled,
    main_loop::Task,
    LspError, Result,
};

pub(crate) struct RequestDispatcher<'a> {
    pub(crate) req: Option<lsp_server::Request>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> RequestDispatcher<'a> {
    /// Dispatches the request onto the current thread
    pub(crate) fn on_sync<R>(
        &mut self,
        f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let world = panic::AssertUnwindSafe(&mut *self.global_state);

        let response = panic::catch_unwind(move || {
            let _pctx = stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params));
            let result = f(world.0, params);
            result_to_response::<R>(id, result)
        })
        .map_err(|_err| format!("sync task {:?} panicked", R::METHOD))?;
        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto thread pool
    pub(crate) fn on<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> &mut Self
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + Send + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params) = match self.parse::<R>() {
            Some(it) => it,
            None => return self,
        };

        self.global_state.task_pool.handle.spawn({
            let world = self.global_state.snapshot();

            move || {
                let _pctx =
                    stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params));
                let result = f(world, params);
                Task::Response(result_to_response::<R>(id, result))
            }
        });

        self
    }

    pub(crate) fn finish(&mut self) {
        if let Some(req) = self.req.take() {
            log::error!("unknown request: {:?}", req);
            let response = lsp_server::Response::new_err(
                req.id,
                lsp_server::ErrorCode::MethodNotFound as i32,
                "unknown request".to_string(),
            );
            self.global_state.respond(response);
        }
    }

    fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params)>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + 'static,
    {
        let req = match &self.req {
            Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
            _ => return None,
        };

        let res = crate::from_json(R::METHOD, req.params);
        match res {
            Ok(params) => return Some((req.id, params)),
            Err(err) => {
                let response = lsp_server::Response::new_err(
                    req.id,
                    lsp_server::ErrorCode::InvalidParams as i32,
                    err.to_string(),
                );
                self.global_state.respond(response);
                return None;
            }
        }
    }
}

fn result_to_response<R>(
    id: lsp_server::RequestId,
    result: Result<R::Result>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(resp) => lsp_server::Response::new_ok(id, &resp),
        Err(e) => match e.downcast::<LspError>() {
            Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
            Err(e) => {
                if is_canceled(&*e) {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::ContentModified as i32,
                        "content modified".to_string(),
                    )
                } else {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::InternalError as i32,
                        e.to_string(),
                    )
                }
            }
        },
    }
}

pub(crate) struct NotificationDispatcher<'a> {
    pub(crate) not: Option<lsp_server::Notification>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> NotificationDispatcher<'a> {
    pub(crate) fn on<N>(
        &mut self,
        f: fn(&mut GlobalState, N::Params) -> Result<()>,
    ) -> Result<&mut Self>
    where
        N: lsp_types::notification::Notification + 'static,
        N::Params: DeserializeOwned + Send + 'static,
    {
        let not = match self.not.take() {
            Some(it) => it,
            None => return Ok(self),
        };
        let params = match not.extract::<N::Params>(N::METHOD) {
            Ok(it) => it,
            Err(not) => {
                self.not = Some(not);
                return Ok(self);
            }
        };
        let _pctx = stdx::panic_context::enter(format!("notification: {}", N::METHOD));
        f(self.global_state, params)?;
        Ok(self)
    }

    pub(crate) fn finish(&mut self) {
        if let Some(not) = &self.not {
            if !not.method.starts_with("$/") {
                log::error!("unhandled notification: {:?}", not);
            }
        }
    }
}
<commit_msg>internal: add rust-analyzer version to panic context<commit_after>//! A visitor for downcasting arbitrary request (JSON) into a specific type.
use std::{fmt, panic};

use serde::{de::DeserializeOwned, Serialize};

use crate::{
    global_state::{GlobalState, GlobalStateSnapshot},
    lsp_utils::is_canceled,
    main_loop::Task,
    LspError, Result,
};

pub(crate) struct RequestDispatcher<'a> {
    pub(crate) req: Option<lsp_server::Request>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> RequestDispatcher<'a> {
    /// Dispatches the request onto the current thread
    pub(crate) fn on_sync<R>(
        &mut self,
        f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
    ) -> Result<&mut Self>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params) = match self.parse::<R>() {
            Some(it) => it,
            None => return Ok(self),
        };
        let world = panic::AssertUnwindSafe(&mut *self.global_state);

        let response = panic::catch_unwind(move || {
            let _pctx = stdx::panic_context::enter(format!(
                "\nversion: {}\nrequest: {} {:#?}",
                env!("REV"),
                R::METHOD,
                params
            ));
            let result = f(world.0, params);
            result_to_response::<R>(id, result)
        })
        .map_err(|_err| format!("sync task {:?} panicked", R::METHOD))?;
        self.global_state.respond(response);
        Ok(self)
    }

    /// Dispatches the request onto thread pool
    pub(crate) fn on<R>(
        &mut self,
        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
    ) -> &mut Self
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + Send + fmt::Debug + 'static,
        R::Result: Serialize + 'static,
    {
        let (id, params) = match self.parse::<R>() {
            Some(it) => it,
            None => return self,
        };

        self.global_state.task_pool.handle.spawn({
            let world = self.global_state.snapshot();

            move || {
                let _pctx = stdx::panic_context::enter(format!(
                    "\nversion: {}\nrequest: {} {:#?}",
                    env!("REV"),
                    R::METHOD,
                    params
                ));
                let result = f(world, params);
                Task::Response(result_to_response::<R>(id, result))
            }
        });

        self
    }

    pub(crate) fn finish(&mut self) {
        if let Some(req) = self.req.take() {
            log::error!("unknown request: {:?}", req);
            let response = lsp_server::Response::new_err(
                req.id,
                lsp_server::ErrorCode::MethodNotFound as i32,
                "unknown request".to_string(),
            );
            self.global_state.respond(response);
        }
    }

    fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params)>
    where
        R: lsp_types::request::Request + 'static,
        R::Params: DeserializeOwned + 'static,
    {
        let req = match &self.req {
            Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
            _ => return None,
        };

        let res = crate::from_json(R::METHOD, req.params);
        match res {
            Ok(params) => return Some((req.id, params)),
            Err(err) => {
                let response = lsp_server::Response::new_err(
                    req.id,
                    lsp_server::ErrorCode::InvalidParams as i32,
                    err.to_string(),
                );
                self.global_state.respond(response);
                return None;
            }
        }
    }
}

fn result_to_response<R>(
    id: lsp_server::RequestId,
    result: Result<R::Result>,
) -> lsp_server::Response
where
    R: lsp_types::request::Request + 'static,
    R::Params: DeserializeOwned + 'static,
    R::Result: Serialize + 'static,
{
    match result {
        Ok(resp) => lsp_server::Response::new_ok(id, &resp),
        Err(e) => match e.downcast::<LspError>() {
            Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
            Err(e) => {
                if is_canceled(&*e) {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::ContentModified as i32,
                        "content modified".to_string(),
                    )
                } else {
                    lsp_server::Response::new_err(
                        id,
                        lsp_server::ErrorCode::InternalError as i32,
                        e.to_string(),
                    )
                }
            }
        },
    }
}

pub(crate) struct NotificationDispatcher<'a> {
    pub(crate) not: Option<lsp_server::Notification>,
    pub(crate) global_state: &'a mut GlobalState,
}

impl<'a> NotificationDispatcher<'a> {
    pub(crate) fn on<N>(
        &mut self,
        f: fn(&mut GlobalState, N::Params) -> Result<()>,
    ) -> Result<&mut Self>
    where
        N: lsp_types::notification::Notification + 'static,
        N::Params: DeserializeOwned + Send + 'static,
    {
        let not = match self.not.take() {
            Some(it) => it,
            None => return Ok(self),
        };
        let params = match not.extract::<N::Params>(N::METHOD) {
            Ok(it) => it,
            Err(not) => {
                self.not = Some(not);
                return Ok(self);
            }
        };
        let _pctx = stdx::panic_context::enter(format!(
            "\nversion: {}\nnotification: {}",
            env!("REV"),
            N::METHOD
        ));
        f(self.global_state, params)?;
        Ok(self)
    }

    pub(crate) fn finish(&mut self) {
        if let Some(not) = &self.not {
            if !not.method.starts_with("$/") {
                log::error!("unhandled notification: {:?}", not);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

use orbclient::Renderer;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: bool,
    close: bool,
}

impl Window
where
    A: WindowAdapter,
{
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: true,
            close: false,
        }
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0'
                && key_event.character != '\n'
                && key_event.character != '\u{0}'
            {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        // update clipboard
        let mut clipboard_value = Some(self.window.clipboard());

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw = true;
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => {}
                orbclient::EventOption::None => {}
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Ok(result) = self.render_context.finish_receiver().try_recv() {
            if result {
                self.redraw = true;
            }
        }
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        self.update = true;
                        self.redraw = true;
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw = true;
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw = true;
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw {
            if let Some(data) = self.render_context.data() {
                let color_data: Vec<orbclient::Color> =
                    data.iter().map(|v| orbclient::Color { data: *v }).collect();

                if color_data.len() == self.window.data().len() {
                    self.window
                        .data_mut()
                        .clone_from_slice(color_data.as_slice());

                    // CONSOLE.time_end("render");
                    self.redraw = false;
                    //super::CONSOLE.time_end("complete");
                }
            }

            self.window.sync();
        }
    }
}
<commit_msg>clippy fix<commit_after>use std::sync::mpsc;

use super::MouseState;
use crate::{
    event::{ButtonState, Key, KeyEvent, MouseButton, MouseEvent},
    render::RenderContext2D,
    window_adapter::WindowAdapter,
    WindowRequest,
};

use orbclient::Renderer;

use orbtk_utils::Point;

/// Represents a wrapper for a orbclient window. It handles events, propagate them to
/// the window adapter and handles the update and render pipeline.
pub struct Window
where
    A: WindowAdapter,
{
    window: orbclient::Window,
    adapter: A,
    render_context: RenderContext2D,
    request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    //window_state: WindowState,
    mouse: MouseState,
    update: bool,
    redraw: bool,
    close: bool,
}

impl Window
where
    A: WindowAdapter,
{
    pub fn new(
        window: orbclient::Window,
        adapter: A,
        render_context: RenderContext2D,
        request_receiver: Option<mpsc::Receiver<WindowRequest>>,
    ) -> Self {
        Window {
            window,
            adapter,
            render_context,
            request_receiver,
            // window_state: WindowState::default(),
            mouse: MouseState::default(),
            update: true,
            redraw: true,
            close: false,
        }
    }
}

impl Window
where
    A: WindowAdapter,
{
    /// Check if the window is open.
    pub fn is_open(&self) -> bool {
        !self.close
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            position: Point::new(self.mouse.mouse_pos.0 as f64, self.mouse.mouse_pos.1 as f64),
            button,
            state,
        });
    }

    fn push_key_event(&mut self, key_event: orbclient::KeyEvent) {
        let mut key = Key::from(key_event.character);
        let state = {
            if key_event.pressed {
                ButtonState::Down
            } else {
                ButtonState::Up
            }
        };

        let text = {
            if key_event.character != '\0' && key_event.character != '\n' {
                key_event.character.to_string()
            } else {
                match key_event.scancode {
                    orbclient::K_BKSP => key = Key::Backspace,
                    orbclient::K_LEFT => key = Key::Left,
                    orbclient::K_RIGHT => key = Key::Right,
                    orbclient::K_UP => key = Key::Up,
                    orbclient::K_DOWN => key = Key::Down,
                    orbclient::K_DEL => key = Key::Delete,
                    orbclient::K_ENTER => key = Key::Enter,
                    orbclient::K_CTRL => key = Key::Control,
                    orbclient::K_LEFT_SHIFT => key = Key::ShiftL,
                    orbclient::K_RIGHT_SHIFT => key = Key::ShiftR,
                    orbclient::K_ALT => key = Key::Alt,
                    orbclient::K_ESC => key = Key::Escape,
                    orbclient::K_CAPS => key = Key::CapsLock,
                    orbclient::K_HOME => {
                        key = Key::Home;
                    }
                    _ => key = Key::Unknown,
                };
                String::default()
            }
        };

        self.adapter.key_event(KeyEvent { key, text, state });
    }

    /// Updates the clipboard.
    pub fn update_clipboard(&mut self) {
        // update clipboard
        let mut clipboard_value = Some(self.window.clipboard());

        self.adapter.clipboard_update(&mut clipboard_value);

        if let Some(value) = clipboard_value {
            self.window.set_clipboard(value.as_str());
        }
    }

    /// Drain events and propagate the events to the adapter.
    pub fn drain_events(&mut self) {
        for event in self.window.events() {
            match event.to_option() {
                orbclient::EventOption::Key(event) => {
                    self.push_key_event(event);
                    self.update = true;
                }
                orbclient::EventOption::Mouse(event) => {
                    self.mouse.mouse_pos = (event.x as f32, event.y as f32);
                    self.adapter.mouse(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::MouseRelative(_) => {}
                orbclient::EventOption::Button(event) => {
                    if event.left != self.mouse.button_left {
                        if event.left {
                            self.push_mouse_event(true, MouseButton::Left);
                        } else {
                            self.push_mouse_event(false, MouseButton::Left);
                        }
                        self.mouse.button_left = event.left;
                        self.update = true;
                    }

                    if event.middle != self.mouse.button_middle {
                        if event.middle {
                            self.push_mouse_event(true, MouseButton::Middle);
                        } else {
                            self.push_mouse_event(false, MouseButton::Middle);
                        }
                        self.mouse.button_middle = event.middle;
                        self.update = true;
                    }

                    if event.right != self.mouse.button_right {
                        if event.right {
                            self.push_mouse_event(true, MouseButton::Right);
                        } else {
                            self.push_mouse_event(false, MouseButton::Right);
                        }
                        self.mouse.button_right = event.right;
                        self.update = true;
                    }
                }
                orbclient::EventOption::Scroll(event) => {
                    self.adapter.scroll(event.x as f64, event.y as f64);
                    self.update = true;
                }
                orbclient::EventOption::Quit(_) => {
                    self.close = true;
                    self.update = true
                }
                orbclient::EventOption::Focus(_) => {}
                orbclient::EventOption::Move(_) => {}
                orbclient::EventOption::Resize(event) => {
                    self.adapter.resize(event.width as f64, event.height as f64);
                    self.render_context
                        .resize(event.width as f64, event.height as f64);
                    self.update = true;
                    self.redraw = true;
                }
                orbclient::EventOption::Screen(_) => {}
                orbclient::EventOption::Clipboard(_) => {}
                orbclient::EventOption::Drop(event) => {
                    self.window.sync_path();
                    if let Some(text) = self.window.pop_drop_content() {
                        if event.kind == orbclient::DROP_FILE {
                            self.adapter.file_drop_event(text);
                        } else {
                            self.adapter.text_drop_event(text);
                        }
                    }
                }
                orbclient::EventOption::Unknown(_) => {}
                orbclient::EventOption::None => {}
            }
        }
    }

    /// Receives window request from the application and handles them.
    pub fn receive_requests(&mut self) {
        if let Ok(result) = self.render_context.finish_receiver().try_recv() {
            if result {
                self.redraw = true;
            }
        }
        if let Some(request_receiver) = &self.request_receiver {
            for request in request_receiver.try_iter() {
                match request {
                    WindowRequest::Redraw => {
                        self.update = true;
                        self.redraw = true;
                    }
                    WindowRequest::ChangeTitle(title) => {
                        self.window.set_title(title.as_str());
                        self.update = true;
                        self.redraw = true;
                    }
                    WindowRequest::Close => {
                        self.close = true;
                    }
                }
            }
        }
    }

    /// Runs update on the adapter.
    pub fn update(&mut self) {
        //super::CONSOLE.time("complete");
        if !self.update {
            return;
        }
        self.adapter.run(&mut self.render_context);
        self.update = false;
        self.redraw = true;
    }

    /// Swaps the current frame buffer.
    pub fn render(&mut self) {
        if self.redraw {
            if let Some(data) = self.render_context.data() {
                let color_data: Vec<orbclient::Color> =
                    data.iter().map(|v| orbclient::Color { data: *v }).collect();

                if color_data.len() == self.window.data().len() {
                    self.window
                        .data_mut()
                        .clone_from_slice(color_data.as_slice());

                    // CONSOLE.time_end("render");
                    self.redraw = false;
                    //super::CONSOLE.time_end("complete");
                }
            }

            self.window.sync();
        }
    }
}
<|endoftext|>