<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use hyper;
use hyper::client::Client;
use mdo::option::{bind, ret};
use super::ToJson;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn bano2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let res: Vec<_> = es_wrapper.search_and_filter("20", |_| true).collect();
    assert_eq!(res.len(), 2);

    // after an import, we should have 1 index, and some aliases to this index
    let client = Client::new();
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(first_indexes.len(), 1);
    // our index should be aliased by the master_index + an alias over the document type + dataset
    let aliases = mdo! {
         s =<< raw_indexes.get(first_indexes.first().unwrap());
         s =<< s.as_object();
         s =<< s.get("aliases");
         s =<< s.as_object();
         ret ret(s.keys().cloned().collect())
     }
        .unwrap_or_else(Vec::new);
    // for the moment 'munin' is hard coded, but hopefully that will change
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);

    // then we import again the bano file:
    info!("importing again {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    // we should still have only one index (but a different one)
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let final_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(final_indexes.len(), 1);
    assert!(final_indexes != first_indexes);

    let aliases = mdo! {
        s =<< raw_indexes.get(final_indexes.first().unwrap());
        s =<< s.as_object();
        s =<< s.get("aliases");
        s =<< s.as_object();
        ret ret(s.keys().cloned().collect())
    }
        .unwrap_or_else(|| vec![]);
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);
}
<commit_msg>mini correction<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use hyper;
use hyper::client::Client;
use mdo::option::{bind, ret};
use super::ToJson;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn bano2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let res: Vec<_> = es_wrapper.search_and_filter("20", |_| true).collect();
    assert_eq!(res.len(), 2);

    // after an import, we should have 1 index, and some aliases to this index
    let client = Client::new();
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(first_indexes.len(), 1);
    // our index should be aliased by the master_index + an alias over the document type + dataset
    let aliases = mdo! {
         s =<< raw_indexes.get(first_indexes.first().unwrap());
         s =<< s.as_object();
         s =<< s.get("aliases");
         s =<< s.as_object();
         ret ret(s.keys().cloned().collect())
     }
        .unwrap_or_else(Vec::new);
    // for the moment 'munin' is hard coded, but hopefully that will change
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);

    // then we import again the bano file:
    info!("importing again {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    // we should still have only one index (but a different one)
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let final_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(final_indexes.len(), 1);
    assert!(final_indexes != first_indexes);

    let aliases = mdo! {
        s =<< raw_indexes.get(final_indexes.first().unwrap());
        s =<< s.as_object();
        s =<< s.get("aliases");
        s =<< s.as_object();
        ret ret(s.keys().cloned().collect())
    }
        .unwrap_or_else(Vec::new);
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);
}
<|endoftext|>


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

use crate::{
    backup_types::{
        epoch_ending::restore::EpochHistoryRestoreController,
        state_snapshot::restore::{StateSnapshotRestoreController, StateSnapshotRestoreOpt},
        transaction::restore::TransactionRestoreBatchController,
    },
    metadata,
    metadata::{cache::MetadataCacheOpt, TransactionBackupMeta},
    metrics::restore::{
        COORDINATOR_FAIL_TS, COORDINATOR_START_TS, COORDINATOR_SUCC_TS, COORDINATOR_TARGET_VERSION,
    },
    storage::BackupStorage,
    utils::{unix_timestamp_sec, GlobalRestoreOptions, RestoreRunMode},
};
use anyhow::{bail, Result};
use diem_logger::prelude::*;
use diem_types::transaction::Version;
use std::sync::Arc;
use structopt::StructOpt;

#[derive(StructOpt)]
pub struct RestoreCoordinatorOpt {
    #[structopt(flatten)]
    pub metadata_cache_opt: MetadataCacheOpt,
    #[structopt(
        long,
        help = "Replay all transactions, don't try to use a state snapshot."
    )]
    pub replay_all: bool,
}

pub struct RestoreCoordinator {
    storage: Arc<dyn BackupStorage>,
    global_opt: GlobalRestoreOptions,
    metadata_cache_opt: MetadataCacheOpt,
    replay_all: bool,
}

impl RestoreCoordinator {
    pub fn new(
        opt: RestoreCoordinatorOpt,
        global_opt: GlobalRestoreOptions,
        storage: Arc<dyn BackupStorage>,
    ) -> Self {
        Self {
            storage,
            global_opt,
            metadata_cache_opt: opt.metadata_cache_opt,
            replay_all: opt.replay_all,
        }
    }

    pub async fn run(self) -> Result<()> {
        info!("Restore coordinator started.");
        COORDINATOR_START_TS.set(unix_timestamp_sec());

        let ret = self.run_impl().await;

        if let Err(e) = &ret {
            error!(
                error = ?e,
                "Restore coordinator failed."
            );
            COORDINATOR_FAIL_TS.set(unix_timestamp_sec());
        } else {
            info!("Restore coordinator exiting with success.");
            COORDINATOR_SUCC_TS.set(unix_timestamp_sec());
        }

        ret
    }

    async fn run_impl(self) -> Result<()> {
        let metadata_view = metadata::cache::sync_and_load(
            &self.metadata_cache_opt,
            Arc::clone(&self.storage),
            self.global_opt.concurrent_downloads,
        )
        .await?;

        let transactions = metadata_view.select_transaction_backups(0, self.target_version())?;
        let actual_target_version = self.get_actual_target_version(&transactions)?;
        let epoch_endings = metadata_view.select_epoch_ending_backups(actual_target_version)?;
        let state_snapshot = if self.replay_all {
            None
        } else {
            metadata_view.select_state_snapshot(actual_target_version)?
        };
        let replay_transactions_from_version = match &state_snapshot {
            Some(b) => b.version + 1,
            None => 0,
        };
        COORDINATOR_TARGET_VERSION.set(actual_target_version as i64);
        info!("Planned to restore to version {}.", actual_target_version);
        let txn_resume_point = match self.global_opt.run_mode.as_ref() {
            RestoreRunMode::Restore { restore_handler } => {
                restore_handler.get_next_expected_transaction_version()?
            }
            RestoreRunMode::Verify => {
                info!("This is a dry run.");
                0
            }
        };
        if txn_resume_point > 0 {
            warn!(
                "DB has existing transactions, will skip transaction backups before version {}",
                txn_resume_point
            );
        }

        let epoch_history = Arc::new(
            EpochHistoryRestoreController::new(
                epoch_endings
                    .into_iter()
                    .map(|backup| backup.manifest)
                    .collect(),
                self.global_opt.clone(),
                self.storage.clone(),
            )
            .run()
            .await?,
        );

        if let Some(backup) = state_snapshot {
            StateSnapshotRestoreController::new(
                StateSnapshotRestoreOpt {
                    manifest_handle: backup.manifest,
                    version: backup.version,
                },
                self.global_opt.clone(),
                Arc::clone(&self.storage),
                Some(Arc::clone(&epoch_history)),
            )
            .run()
            .await?;
        }

        let txn_manifests = transactions
            .into_iter()
            .skip_while(|b| b.last_version < txn_resume_point)
            .map(|b| b.manifest)
            .collect();
        TransactionRestoreBatchController::new(
            self.global_opt,
            self.storage,
            txn_manifests,
            Some(replay_transactions_from_version),
            Some(epoch_history),
        )
        .run()
        .await?;

        Ok(())
    }
}

impl RestoreCoordinator {
    fn target_version(&self) -> Version {
        self.global_opt.target_version
    }

    fn get_actual_target_version(
        &self,
        transaction_backups: &[TransactionBackupMeta],
    ) -> Result<Version> {
        if let Some(b) = transaction_backups.last() {
            if b.last_version > self.target_version() {
                Ok(self.target_version())
            } else {
                warn!(
                    "Can't find transaction backup containing the target version, \
                    will restore as much as possible"
                );
                Ok(b.last_version)
            }
        } else {
            bail!("No transaction backup found.")
        }
    }
}
<commit_msg>[backup] "db-restore auto": add --ledger-history-start-version<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    backup_types::{
        epoch_ending::restore::EpochHistoryRestoreController,
        state_snapshot::restore::{StateSnapshotRestoreController, StateSnapshotRestoreOpt},
        transaction::restore::TransactionRestoreBatchController,
    },
    metadata,
    metadata::{cache::MetadataCacheOpt, TransactionBackupMeta},
    metrics::restore::{
        COORDINATOR_FAIL_TS, COORDINATOR_START_TS, COORDINATOR_SUCC_TS, COORDINATOR_TARGET_VERSION,
    },
    storage::BackupStorage,
    utils::{unix_timestamp_sec, GlobalRestoreOptions, RestoreRunMode},
};
use anyhow::{bail, Result};
use diem_logger::prelude::*;
use diem_types::transaction::Version;
use std::sync::Arc;
use structopt::StructOpt;

#[derive(StructOpt)]
pub struct RestoreCoordinatorOpt {
    #[structopt(flatten)]
    pub metadata_cache_opt: MetadataCacheOpt,
    #[structopt(
        long,
        help = "Replay all transactions, don't try to use a state snapshot."
    )]
    pub replay_all: bool,
    #[structopt(
        long,
        default_value = "0",
        help = "Ignore restoring the ledger history (transactions and events) before this version \
                if possible"
    )]
    pub ledger_history_start_version: Version,
    #[structopt(long, help = "Skip restoring epoch ending info, used for debugging.")]
    pub skip_epoch_endings: bool,
}

pub struct RestoreCoordinator {
    storage: Arc<dyn BackupStorage>,
    global_opt: GlobalRestoreOptions,
    metadata_cache_opt: MetadataCacheOpt,
    replay_all: bool,
    ledger_history_start_version: Version,
    skip_epoch_endings: bool,
}

impl RestoreCoordinator {
    pub fn new(
        opt: RestoreCoordinatorOpt,
        global_opt: GlobalRestoreOptions,
        storage: Arc<dyn BackupStorage>,
    ) -> Self {
        Self {
            storage,
            global_opt,
            metadata_cache_opt: opt.metadata_cache_opt,
            replay_all: opt.replay_all,
            ledger_history_start_version: opt.ledger_history_start_version,
            skip_epoch_endings: opt.skip_epoch_endings,
        }
    }

    pub async fn run(self) -> Result<()> {
        info!("Restore coordinator started.");
        COORDINATOR_START_TS.set(unix_timestamp_sec());

        let ret = self.run_impl().await;

        if let Err(e) = &ret {
            error!(
                error = ?e,
                "Restore coordinator failed."
            );
            COORDINATOR_FAIL_TS.set(unix_timestamp_sec());
        } else {
            info!("Restore coordinator exiting with success.");
            COORDINATOR_SUCC_TS.set(unix_timestamp_sec());
        }

        ret
    }

    async fn run_impl(self) -> Result<()> {
        let metadata_view = metadata::cache::sync_and_load(
            &self.metadata_cache_opt,
            Arc::clone(&self.storage),
            self.global_opt.concurrent_downloads,
        )
        .await?;

        let mut transactions =
            metadata_view.select_transaction_backups(0, self.target_version())?;
        let actual_target_version = self.get_actual_target_version(&transactions)?;
        let epoch_endings = metadata_view.select_epoch_ending_backups(actual_target_version)?;
        let state_snapshot = if self.replay_all {
            None
        } else {
            metadata_view.select_state_snapshot(actual_target_version)?
        };
        let replay_transactions_from_version = match &state_snapshot {
            Some(b) => b.version + 1,
            None => 0,
        };
        COORDINATOR_TARGET_VERSION.set(actual_target_version as i64);
        info!("Planned to restore to version {}.", actual_target_version);

        let txn_resume_point = match self.global_opt.run_mode.as_ref() {
            RestoreRunMode::Restore { restore_handler } => {
                restore_handler.get_next_expected_transaction_version()?
            }
            RestoreRunMode::Verify => {
                info!("This is a dry run.");
                0
            }
        };
        let start_version = std::cmp::min(
            self.ledger_history_start_version,
            state_snapshot.as_ref().map(|s| s.version + 1).unwrap_or(0),
        );
        transactions = transactions
            .into_iter()
            .skip_while(|p| p.last_version < start_version)
            .collect();
        if let Some(actual_start_version) = transactions.first().map(|t| t.first_version) {
            if txn_resume_point > 0 {
                if actual_start_version > txn_resume_point {
                    panic!(
                        "DB has transactions till {}, requesting to add transactions from {}, might \
                    result in non-continuous ledger history, aborting. Try to adjust the \
                    --ledger_history_start_version flag.",
                        txn_resume_point,
                        self.ledger_history_start_version,
                    );
                }
                warn!(
                    "DB has existing transactions, will skip transaction backups before version {}",
                    txn_resume_point
                );
                transactions = transactions
                    .into_iter()
                    .skip_while(|p| p.last_version < txn_resume_point)
                    .collect();
            }
        }

        let epoch_history = if self.skip_epoch_endings {
            None
        } else {
            Some(Arc::new(
                EpochHistoryRestoreController::new(
                    epoch_endings
                        .into_iter()
                        .map(|backup| backup.manifest)
                        .collect(),
                    self.global_opt.clone(),
                    self.storage.clone(),
                )
                .run()
                .await?,
            ))
        };

        if let Some(backup) = state_snapshot {
            StateSnapshotRestoreController::new(
                StateSnapshotRestoreOpt {
                    manifest_handle: backup.manifest,
                    version: backup.version,
                },
                self.global_opt.clone(),
                Arc::clone(&self.storage),
                epoch_history.clone(),
            )
            .run()
            .await?;
        }

        let txn_manifests = transactions.into_iter().map(|b| b.manifest).collect();
        TransactionRestoreBatchController::new(
            self.global_opt,
            self.storage,
            txn_manifests,
            Some(replay_transactions_from_version),
            epoch_history,
        )
        .run()
        .await?;

        Ok(())
    }
}

impl RestoreCoordinator {
    fn target_version(&self) -> Version {
        self.global_opt.target_version
    }

    fn get_actual_target_version(
        &self,
        transaction_backups: &[TransactionBackupMeta],
    ) -> Result<Version> {
        if let Some(b) = transaction_backups.last() {
            if b.last_version > self.target_version() {
                Ok(self.target_version())
            } else {
                warn!(
                    "Can't find transaction backup containing the target version, \
                    will restore as much as possible"
                );
                Ok(b.last_version)
            }
        } else {
            bail!("No transaction backup found.")
        }
    }
}
<|endoftext|>


<commit_before>//! A lazily fill Cell, but with frozen contents.
//!
//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
//! the entire object, but only of the borrows returned. A `LazyCell` is a
//! variation on `RefCell` which allows borrows tied to the lifetime of the
//! outer object.
//!
//! The limitation of a `LazyCell` is that after initialized, it can never be
//! modified unless you've otherwise got a `&mut` reference

use std::cell::UnsafeCell;

#[derive(Debug)]
pub struct LazyCell<T> {
    inner: UnsafeCell<Option<T>>,
}

impl<T> LazyCell<T> {
    /// Creates a new empty lazy cell.
    pub fn new() -> LazyCell<T> {
        LazyCell { inner: UnsafeCell::new(None) }
    }

    /// Put a value into this cell.
    ///
    /// This function will fail if the cell has already been filled.
    pub fn fill(&self, t: T) -> Result<(), T> {
        unsafe {
            let slot = self.inner.get();
            if (*slot).is_none() {
                *slot = Some(t);
                Ok(())
            } else {
                Err(t)
            }
        }
    }

    /// Borrows the contents of this lazy cell for the duration of the cell
    /// itself.
    ///
    /// This function will return `Some` if the cell has been previously
    /// initialized, and `None` if it has not yet been initialized.
    pub fn borrow(&self) -> Option<&T> {
        unsafe {
            (*self.inner.get()).as_ref()
        }
    }

    /// Same as `borrow`, but the mutable version
    pub fn borrow_mut(&mut self) -> Option<&mut T> {
        unsafe {
            (*self.inner.get()).as_mut()
        }
    }

    /// Consumes this `LazyCell`, returning the underlying value.
    pub fn into_inner(self) -> Option<T> {
        unsafe {
            self.inner.into_inner()
        }
    }

    /// Borrows the contents of this lazy cell, initializing it if necessary.
    pub fn get_or_try_init<Error, F>(&self, init: F) -> Result<&T, Error>
        where F: FnOnce() -> Result<T, Error>
    {
        if self.borrow().is_none() && self.fill(init()?).is_err() {
            unreachable!();
        }
        Ok(self.borrow().unwrap())
    }
}
<commit_msg>Auto merge of #4972 - varkor:lazy-cell-unused-unsafe, r=alexcrichton<commit_after>//! A lazily fill Cell, but with frozen contents.
//!
//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
//! the entire object, but only of the borrows returned. A `LazyCell` is a
//! variation on `RefCell` which allows borrows tied to the lifetime of the
//! outer object.
//!
//! The limitation of a `LazyCell` is that after initialized, it can never be
//! modified unless you've otherwise got a `&mut` reference

use std::cell::UnsafeCell;

#[derive(Debug)]
pub struct LazyCell<T> {
    inner: UnsafeCell<Option<T>>,
}

impl<T> LazyCell<T> {
    /// Creates a new empty lazy cell.
    pub fn new() -> LazyCell<T> {
        LazyCell { inner: UnsafeCell::new(None) }
    }

    /// Put a value into this cell.
    ///
    /// This function will fail if the cell has already been filled.
    pub fn fill(&self, t: T) -> Result<(), T> {
        unsafe {
            let slot = self.inner.get();
            if (*slot).is_none() {
                *slot = Some(t);
                Ok(())
            } else {
                Err(t)
            }
        }
    }

    /// Borrows the contents of this lazy cell for the duration of the cell
    /// itself.
    ///
    /// This function will return `Some` if the cell has been previously
    /// initialized, and `None` if it has not yet been initialized.
    pub fn borrow(&self) -> Option<&T> {
        unsafe {
            (*self.inner.get()).as_ref()
        }
    }

    /// Same as `borrow`, but the mutable version
    pub fn borrow_mut(&mut self) -> Option<&mut T> {
        unsafe {
            (*self.inner.get()).as_mut()
        }
    }

    /// Consumes this `LazyCell`, returning the underlying value.
    #[allow(unused_unsafe)]
    pub fn into_inner(self) -> Option<T> {
        unsafe {
            self.inner.into_inner()
        }
    }

    /// Borrows the contents of this lazy cell, initializing it if necessary.
    pub fn get_or_try_init<Error, F>(&self, init: F) -> Result<&T, Error>
        where F: FnOnce() -> Result<T, Error>
    {
        if self.borrow().is_none() && self.fill(init()?).is_err() {
            unreachable!();
        }
        Ok(self.borrow().unwrap())
    }
}
<|endoftext|>


<commit_before>// min-lldb-version: 310

// We have to ignore android because of this issue:
// https://github.com/rust-lang/rust/issues/74847
// ignore-android
//
// We need to use inline assembly, so just use one platform
// only-x86_64

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:info args
// gdb-check:No arguments.
// gdb-command:continue

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:frame variable
// lldbg-check:(unsigned long) = 111 (unsigned long) = 222
// lldbr-check:(unsigned long) = 111 (unsigned long) = 222
// lldb-command:continue

#![feature(asm)]
#![feature(naked_functions)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]

fn main() {
    naked(111, 222);
}

#[naked]
fn naked(x: usize, y: usize) {
    unsafe { asm!("ret"); } // #break
}
<commit_msg>Apply `extern "C"` calling convention<commit_after>// min-lldb-version: 310

// We have to ignore android because of this issue:
// https://github.com/rust-lang/rust/issues/74847
// ignore-android
//
// We need to use inline assembly, so just use one platform
// only-x86_64

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:info args
// gdb-check:No arguments.
// gdb-command:continue

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:frame variable
// lldbg-check:(unsigned long) = 111 (unsigned long) = 222
// lldbr-check:(unsigned long) = 111 (unsigned long) = 222
// lldb-command:continue

#![feature(asm)]
#![feature(naked_functions)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]

fn main() {
    naked(111, 222);
}

#[naked]
extern "C" fn naked(x: usize, y: usize) {
    unsafe { asm!("ret"); } // #break
}
<|endoftext|>


<commit_before>extern crate rusty_secrets;

use rusty_secrets::sss::recover_secret;

#[test]
#[should_panic(expected = "EmptyShares")]
fn test_recover_no_shares() {
    for signed in &[true, false] {
        let shares = vec![];
        recover_secret(&shares, *signed).unwrap();
    }
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_2_parts_share() {
    let share1 = "2-1-CgmKQZHMO+5n5pU".to_string();
    let share2 = "2-2".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "IntegerParsingError")]
fn test_recover_incorrect_share_num() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-DEFINITLY_NAN-CgkAnUgP3lfwjyM".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_0_share_num() {
    let share1 = "2-0-1YAYwmOHqZ69jA".to_string();
    let share2 = "2-1-YJZQDGm22Y77Gw".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_invalid_b64() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-2-YJZQDG((((m22Y)))77Gw".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "DuplicateShareId")]
fn test_recover_duplicate_shares_number() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-1-CgkAnUgP3lfwjyM".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "DuplicateShareData")]
fn test_recover_duplicate_shares_data() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-2-CgnlCxRNtnkzENE".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "MissingShares")]
fn test_recover_too_few_shares() {
    let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string();
    let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}
<commit_msg>Add a test for issue #43.<commit_after>extern crate rusty_secrets;

use rusty_secrets::sss::{recover_secret, split_secret};

#[test]
#[should_panic(expected = "EmptyShares")]
fn test_recover_no_shares() {
    for signed in &[true, false] {
        let shares = vec![];
        recover_secret(&shares, *signed).unwrap();
    }
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_2_parts_share() {
    let share1 = "2-1-CgmKQZHMO+5n5pU".to_string();
    let share2 = "2-2".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "IntegerParsingError")]
fn test_recover_incorrect_share_num() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-DEFINITLY_NAN-CgkAnUgP3lfwjyM".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_0_share_num() {
    let share1 = "2-0-1YAYwmOHqZ69jA".to_string();
    let share2 = "2-1-YJZQDGm22Y77Gw".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "ShareParsingError")]
fn test_recover_invalid_b64() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-2-YJZQDG((((m22Y)))77Gw".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "DuplicateShareId")]
fn test_recover_duplicate_shares_number() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-1-CgkAnUgP3lfwjyM".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "DuplicateShareData")]
fn test_recover_duplicate_shares_data() {
    let share1 = "2-1-CgnlCxRNtnkzENE".to_string();
    let share2 = "2-2-CgnlCxRNtnkzENE".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

#[test]
#[should_panic(expected = "MissingShares")]
fn test_recover_too_few_shares() {
    let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string();
    let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string();

    let shares = vec![share1, share2];

    recover_secret(&shares, false).unwrap();
}

// See https://github.com/SpinResearch/RustySecrets/issues/43
#[test]
fn test_recover_too_few_shares_bug() {
    let original = b"Test for issue #43".to_vec();
    let shares = split_secret(4, 5, &original, false).unwrap();
    let mut share_1 = shares[0].clone().into_bytes();
    let mut share_2 = shares[3].clone().into_bytes();

    share_1[0] = '2' as u8;
    share_2[0] = '2' as u8;

    let sub_shares = vec![
        String::from_utf8_lossy(&share_1).into_owned(),
        String::from_utf8_lossy(&share_2).into_owned(),
    ];

    match recover_secret(&sub_shares, false) {
        Err(_) => assert!(true),
        Ok(recovered) => assert_ne!(original, recovered),
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*};

fn main() {
    atomic_bool();
    atomic_isize();
    atomic_u64();
    atomic_fences();
}

fn atomic_bool() {
    static mut ATOMIC: AtomicBool = AtomicBool::new(false);

    unsafe {
        assert_eq!(*ATOMIC.get_mut(), false);
        ATOMIC.store(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_or(false, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_and(false, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), false);
        ATOMIC.fetch_nand(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_xor(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), false);
    }
}

fn atomic_isize() {
    static ATOMIC: AtomicIsize = AtomicIsize::new(0);

    // Make sure trans can emit all the intrinsics correctly
    assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0));
    assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1));
    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();

    ATOMIC.store(0, SeqCst);

    assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0));
    assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1));
    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
}

fn atomic_u64() {
    static ATOMIC: AtomicU64 = AtomicU64::new(0);

    ATOMIC.store(1, SeqCst);
    assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1));
    assert_eq!(
        ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire),
        Ok(1)
    );
    assert_eq!(ATOMIC.load(Relaxed), 0x100);
}

fn atomic_fences() {
    fence(SeqCst);
    fence(Release);
    fence(Acquire);
}
<commit_msg>Auto merge of #981 - RalfJung:atomic, r=RalfJung<commit_after>use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*};

fn main() {
    atomic_bool();
    atomic_isize();
    atomic_u64();
    atomic_fences();
}

fn atomic_bool() {
    static mut ATOMIC: AtomicBool = AtomicBool::new(false);

    unsafe {
        assert_eq!(*ATOMIC.get_mut(), false);
        ATOMIC.store(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_or(false, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_and(false, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), false);
        ATOMIC.fetch_nand(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), true);
        ATOMIC.fetch_xor(true, SeqCst);
        assert_eq!(*ATOMIC.get_mut(), false);
    }
}

fn atomic_isize() {
    static ATOMIC: AtomicIsize = AtomicIsize::new(0);

    // Make sure trans can emit all the intrinsics correctly
    assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0));
    assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1));
    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
    ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();

    ATOMIC.store(0, SeqCst);

    assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0));
    assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1));
    assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1));
    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
    ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
}

fn atomic_u64() {
    static ATOMIC: AtomicU64 = AtomicU64::new(0);

    ATOMIC.store(1, SeqCst);
    assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1));
    assert_eq!(
        ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire),
        Ok(1)
    );
    assert_eq!(ATOMIC.load(Relaxed), 0x100);
}

fn atomic_fences() {
    fence(SeqCst);
    fence(Release);
    fence(Acquire);
    fence(AcqRel);
}
<|endoftext|>


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

mod cargo_workspace;
mod project_json;
mod sysroot;
mod cfg_flag;
mod workspace;

use std::{
    fs::{read_dir, ReadDir},
    io,
    process::Command,
};

use anyhow::{bail, Context, Result};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashSet;

pub use crate::{
    cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind},
    project_json::{ProjectJson, ProjectJsonData},
    sysroot::Sysroot,
    workspace::{PackageRoot, ProjectWorkspace},
};

pub use proc_macro_api::ProcMacroClient;

#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum ProjectManifest {
    ProjectJson(AbsPathBuf),
    CargoToml(AbsPathBuf),
}

impl ProjectManifest {
    pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> {
        if path.ends_with("rust-project.json") {
            return Ok(ProjectManifest::ProjectJson(path));
        }
        if path.ends_with("Cargo.toml") {
            return Ok(ProjectManifest::CargoToml(path));
        }
        bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
    }

    pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> {
        let mut candidates = ProjectManifest::discover(path)?;
        let res = match candidates.pop() {
            None => bail!("no projects"),
            Some(it) => it,
        };

        if !candidates.is_empty() {
            bail!("more than one project")
        }
        Ok(res)
    }

    pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> {
        if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") {
            return Ok(vec![ProjectManifest::ProjectJson(project_json)]);
        }
        return find_cargo_toml(path)
            .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect());

        fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> {
            match find_in_parent_dirs(path, "Cargo.toml") {
                Some(it) => Ok(vec![it]),
                None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
            }
        }

        fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> {
            if path.ends_with(target_file_name) {
                return Some(path.to_path_buf());
            }

            let mut curr = Some(path);

            while let Some(path) = curr {
                let candidate = path.join(target_file_name);
                if candidate.exists() {
                    return Some(candidate);
                }
                curr = path.parent();
            }

            None
        }

        fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> {
            // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
            entities
                .filter_map(Result::ok)
                .map(|it| it.path().join("Cargo.toml"))
                .filter(|it| it.exists())
                .map(AbsPathBuf::assert)
                .collect()
        }
    }

    pub fn discover_all(paths: &[impl AsRef<AbsPath>]) -> Vec<ProjectManifest> {
        let mut res = paths
            .iter()
            .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok())
            .flatten()
            .collect::<FxHashSet<_>>()
            .into_iter()
            .collect::<Vec<_>>();
        res.sort();
        res
    }
}

fn utf8_stdout(mut cmd: Command) -> Result<String> {
    let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?;
    if !output.status.success() {
        match String::from_utf8(output.stderr) {
            Ok(stderr) if !stderr.is_empty() => {
                bail!("{:?} failed, {}\nstderr:\n{}", cmd, output.status, stderr)
            }
            _ => bail!("{:?} failed, {}", cmd, output.status),
        }
    }
    let stdout = String::from_utf8(output.stdout)?;
    Ok(stdout.trim().to_string())
}
<commit_msg>Make `PackageData`, `TargetData` and `PackageDependency` public<commit_after>//! FIXME: write short doc here

mod cargo_workspace;
mod cfg_flag;
mod project_json;
mod sysroot;
mod workspace;

use std::{
    fs::{read_dir, ReadDir},
    io,
    process::Command,
};

use anyhow::{bail, Context, Result};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashSet;

pub use crate::{
    cargo_workspace::{
        CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData,
        TargetKind,
    },
    project_json::{ProjectJson, ProjectJsonData},
    sysroot::Sysroot,
    workspace::{PackageRoot, ProjectWorkspace},
};

pub use proc_macro_api::ProcMacroClient;

#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum ProjectManifest {
    ProjectJson(AbsPathBuf),
    CargoToml(AbsPathBuf),
}

impl ProjectManifest {
    pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> {
        if path.ends_with("rust-project.json") {
            return Ok(ProjectManifest::ProjectJson(path));
        }
        if path.ends_with("Cargo.toml") {
            return Ok(ProjectManifest::CargoToml(path));
        }
        bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
    }

    pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> {
        let mut candidates = ProjectManifest::discover(path)?;
        let res = match candidates.pop() {
            None => bail!("no projects"),
            Some(it) => it,
        };

        if !candidates.is_empty() {
            bail!("more than one project")
        }
        Ok(res)
    }

    pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> {
        if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") {
            return Ok(vec![ProjectManifest::ProjectJson(project_json)]);
        }
        return find_cargo_toml(path)
            .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect());

        fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> {
            match find_in_parent_dirs(path, "Cargo.toml") {
                Some(it) => Ok(vec![it]),
                None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
            }
        }

        fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> {
            if path.ends_with(target_file_name) {
                return Some(path.to_path_buf());
            }

            let mut curr = Some(path);

            while let Some(path) = curr {
                let candidate = path.join(target_file_name);
                if candidate.exists() {
                    return Some(candidate);
                }
                curr = path.parent();
            }

            None
        }

        fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> {
            // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
            entities
                .filter_map(Result::ok)
                .map(|it| it.path().join("Cargo.toml"))
                .filter(|it| it.exists())
                .map(AbsPathBuf::assert)
                .collect()
        }
    }

    pub fn discover_all(paths: &[impl AsRef<AbsPath>]) -> Vec<ProjectManifest> {
        let mut res = paths
            .iter()
            .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok())
            .flatten()
            .collect::<FxHashSet<_>>()
            .into_iter()
            .collect::<Vec<_>>();
        res.sort();
        res
    }
}

fn utf8_stdout(mut cmd: Command) -> Result<String> {
    let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?;
    if !output.status.success() {
        match String::from_utf8(output.stderr) {
            Ok(stderr) if !stderr.is_empty() => {
                bail!("{:?} failed, {}\nstderr:\n{}", cmd, output.status, stderr)
            }
            _ => bail!("{:?} failed, {}", cmd, output.status),
        }
    }
    let stdout = String::from_utf8(output.stdout)?;
    Ok(stdout.trim().to_string())
}
<|endoftext|>


<commit_before>//! Provides set of implementation for hir's objects that allows get back location in file.

use either::Either;
use hir_def::{
    nameres::{ModuleOrigin, ModuleSource},
    src::{HasChildSource, HasSource as _},
    Lookup, VariantId,
};
use ra_syntax::ast;

use crate::{
    db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, MacroDef,
    Module, Static, Struct, Trait, TypeAlias, TypeParam, Union,
};

pub use hir_expand::InFile;

pub trait HasSource {
    type Ast;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
}

/// NB: Module is !HasSource, because it has two source nodes at the same time:
/// definition and declaration.
impl Module {
    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].definition_source(db.upcast())
    }

    pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
        let def_map = db.crate_def_map(self.id.krate);
        match def_map[self.id.local_id].origin {
            ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
            _ => false,
        }
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].declaration_source(db.upcast())
    }
}

impl HasSource for Field {
    type Ast = FieldSource;
    fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
        let var = VariantId::from(self.parent);
        let src = var.child_source(db.upcast());
        src.map(|it| match it[self.id].clone() {
            Either::Left(it) => FieldSource::Pos(it),
            Either::Right(it) => FieldSource::Named(it),
        })
    }
}
impl HasSource for Struct {
    type Ast = ast::Struct;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Union {
    type Ast = ast::Union;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Enum {
    type Ast = ast::Enum;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for EnumVariant {
    type Ast = ast::Variant;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
        self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
    }
}
impl HasSource for Function {
    type Ast = ast::Fn;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Const {
    type Ast = ast::Const;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Static {
    type Ast = ast::Static;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Trait {
    type Ast = ast::Trait;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for TypeAlias {
    type Ast = ast::TypeAlias;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for MacroDef {
    type Ast = ast::MacroCall;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
        InFile {
            file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
            value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
        }
    }
}
impl HasSource for ImplDef {
    type Ast = ast::Impl;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}

impl HasSource for TypeParam {
    type Ast = Either<ast::Trait, ast::TypeParam>;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }
}
<commit_msg>fix trailing space<commit_after>//! Provides set of implementation for hir's objects that allows get back location in file.

use either::Either;
use hir_def::{
    nameres::{ModuleOrigin, ModuleSource},
    src::{HasChildSource, HasSource as _},
    Lookup, VariantId,
};
use ra_syntax::ast;

use crate::{
    db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, MacroDef,
    Module, Static, Struct, Trait, TypeAlias, TypeParam, Union,
};

pub use hir_expand::InFile;

pub trait HasSource {
    type Ast;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
}

/// NB: Module is !HasSource, because it has two source nodes at the same time:
/// definition and declaration.
impl Module {
    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].definition_source(db.upcast())
    }

    pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
        let def_map = db.crate_def_map(self.id.krate);
        match def_map[self.id.local_id].origin {
            ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
            _ => false,
        }
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].declaration_source(db.upcast())
    }
}

impl HasSource for Field {
    type Ast = FieldSource;
    fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
        let var = VariantId::from(self.parent);
        let src = var.child_source(db.upcast());
        src.map(|it| match it[self.id].clone() {
            Either::Left(it) => FieldSource::Pos(it),
            Either::Right(it) => FieldSource::Named(it),
        })
    }
}
impl HasSource for Struct {
    type Ast = ast::Struct;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Union {
    type Ast = ast::Union;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Enum {
    type Ast = ast::Enum;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for EnumVariant {
    type Ast = ast::Variant;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
        self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
    }
}
impl HasSource for Function {
    type Ast = ast::Fn;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Const {
    type Ast = ast::Const;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Static {
    type Ast = ast::Static;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for Trait {
    type Ast = ast::Trait;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for TypeAlias {
    type Ast = ast::TypeAlias;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}
impl HasSource for MacroDef {
    type Ast = ast::MacroCall;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
        InFile {
            file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
            value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
        }
    }
}
impl HasSource for ImplDef {
    type Ast = ast::Impl;
    fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }
}

impl HasSource for TypeParam {
    type Ast = Either<ast::Trait, ast::TypeParam>;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }
}
<|endoftext|>


<commit_before>use super::*;

#[derive(Debug)]
pub(crate) struct BLinkMaterializer {
    config: Config,
}

impl Materializer for BLinkMaterializer {
    type PageFrag = Frag;

    fn merge<'a, I>(frags: I, config: &Config) -> Self::PageFrag
    where
        I: IntoIterator<Item = &'a Self::PageFrag>,
    {
        let mut frag_iter = frags.into_iter();

        let possible_base = frag_iter
            .next()
            .expect("merge should only be called on non-empty sets of Frag's");

        match possible_base {
            Frag::Base(ref base_node_ref) => {
                let mut base_node = base_node_ref.clone();
                for frag in frag_iter {
                    base_node.apply(frag, config.merge_operator);
                }

                Frag::Base(base_node)
            }
            _ => panic!("non-Base in first element of frags slice"),
        }
    }

    fn size_in_bytes(frag: &Frag) -> usize {
        match *frag {
            Frag::Base(ref node) => std::mem::size_of::<Frag>()
                .saturating_add(node.size_in_bytes() as usize),
            _ => std::mem::size_of::<Frag>(),
        }
    }
}
<commit_msg>Remove state in BLinkMaterializer<commit_after>use super::*;

pub(crate) struct BLinkMaterializer;

impl Materializer for BLinkMaterializer {
    type PageFrag = Frag;

    fn merge<'a, I>(frags: I, config: &Config) -> Self::PageFrag
    where
        I: IntoIterator<Item = &'a Self::PageFrag>,
    {
        let mut frag_iter = frags.into_iter();

        let possible_base = frag_iter
            .next()
            .expect("merge should only be called on non-empty sets of Frag's");

        match possible_base {
            Frag::Base(ref base_node_ref) => {
                let mut base_node = base_node_ref.clone();
                for frag in frag_iter {
                    base_node.apply(frag, config.merge_operator);
                }

                Frag::Base(base_node)
            }
            _ => panic!("non-Base in first element of frags slice"),
        }
    }

    fn size_in_bytes(frag: &Frag) -> usize {
        match *frag {
            Frag::Base(ref node) => std::mem::size_of::<Frag>()
                .saturating_add(node.size_in_bytes() as usize),
            _ => std::mem::size_of::<Frag>(),
        }
    }
}
<|endoftext|>


<commit_before>//! Defines database & queries for name resolution.
use std::sync::Arc;

use hir_expand::{db::AstDatabase, HirFileId};
use ra_db::{salsa, CrateId, SourceDatabase};
use ra_syntax::{ast, SmolStr};

use crate::{
    adt::{EnumData, StructData},
    attr::Attrs,
    body::{scope::ExprScopes, Body, BodySourceMap},
    data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
    docs::Documentation,
    generics::GenericParams,
    lang_item::{LangItemTarget, LangItems},
    nameres::{
        raw::{ImportSourceMap, RawItems},
        CrateDefMap,
    },
    AttrDefId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, ModuleId,
    StaticId, StructOrUnionId, TraitId, TypeAliasId,
};

#[salsa::query_group(InternDatabaseStorage)]
pub trait InternDatabase: SourceDatabase {
    #[salsa::interned]
    fn intern_function(&self, loc: crate::FunctionLoc) -> crate::FunctionId;
    #[salsa::interned]
    fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId;
    #[salsa::interned]
    fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId;
    #[salsa::interned]
    fn intern_const(&self, loc: crate::ConstLoc) -> crate::ConstId;
    #[salsa::interned]
    fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId;
    #[salsa::interned]
    fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId;
    #[salsa::interned]
    fn intern_type_alias(&self, loc: crate::TypeAliasLoc) -> crate::TypeAliasId;
    #[salsa::interned]
    fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId;
}

#[salsa::query_group(DefDatabaseStorage)]
pub trait DefDatabase: InternDatabase + AstDatabase {
    #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
    fn raw_items_with_source_map(
        &self,
        file_id: HirFileId,
    ) -> (Arc<RawItems>, Arc<ImportSourceMap>);

    #[salsa::invoke(RawItems::raw_items_query)]
    fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;

    #[salsa::invoke(CrateDefMap::crate_def_map_query)]
    fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;

    #[salsa::invoke(StructData::struct_data_query)]
    fn struct_data(&self, id: StructOrUnionId) -> Arc<StructData>;

    #[salsa::invoke(EnumData::enum_data_query)]
    fn enum_data(&self, e: EnumId) -> Arc<EnumData>;

    #[salsa::invoke(ImplData::impl_data_query)]
    fn impl_data(&self, e: ImplId) -> Arc<ImplData>;

    #[salsa::invoke(TraitData::trait_data_query)]
    fn trait_data(&self, e: TraitId) -> Arc<TraitData>;

    #[salsa::invoke(TypeAliasData::type_alias_data_query)]
    fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;

    #[salsa::invoke(FunctionData::fn_data_query)]
    fn function_data(&self, func: FunctionId) -> Arc<FunctionData>;

    #[salsa::invoke(ConstData::const_data_query)]
    fn const_data(&self, konst: ConstId) -> Arc<ConstData>;

    #[salsa::invoke(ConstData::static_data_query)]
    fn static_data(&self, konst: StaticId) -> Arc<ConstData>;

    #[salsa::invoke(Body::body_with_source_map_query)]
    fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);

    #[salsa::invoke(Body::body_query)]
    fn body(&self, def: DefWithBodyId) -> Arc<Body>;

    #[salsa::invoke(ExprScopes::expr_scopes_query)]
    fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;

    #[salsa::invoke(GenericParams::generic_params_query)]
    fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;

    #[salsa::invoke(Attrs::attrs_query)]
    fn attrs(&self, def: AttrDefId) -> Attrs;

    #[salsa::invoke(LangItems::module_lang_items_query)]
    fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>;

    #[salsa::invoke(LangItems::crate_lang_items_query)]
    fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;

    #[salsa::invoke(LangItems::lang_item_query)]
    fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;

    // FIXME(https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102)
    // Remove this query completely, in favor of `Attrs::docs` method
    #[salsa::invoke(Documentation::documentation_query)]
    fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
}
<commit_msg>Cleanup imports<commit_after>//! Defines database & queries for name resolution.
use std::sync::Arc;

use hir_expand::{db::AstDatabase, HirFileId};
use ra_db::{salsa, CrateId, SourceDatabase};
use ra_syntax::{ast, SmolStr};

use crate::{
    adt::{EnumData, StructData},
    attr::Attrs,
    body::{scope::ExprScopes, Body, BodySourceMap},
    data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
    docs::Documentation,
    generics::GenericParams,
    lang_item::{LangItemTarget, LangItems},
    nameres::{
        raw::{ImportSourceMap, RawItems},
        CrateDefMap,
    },
    AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
    ImplId, ItemLoc, ModuleId, StaticId, StructOrUnionId, TraitId, TypeAliasId, TypeAliasLoc,
};

#[salsa::query_group(InternDatabaseStorage)]
pub trait InternDatabase: SourceDatabase {
    #[salsa::interned]
    fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
    #[salsa::interned]
    fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> StructOrUnionId;
    #[salsa::interned]
    fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId;
    #[salsa::interned]
    fn intern_const(&self, loc: ConstLoc) -> ConstId;
    #[salsa::interned]
    fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> StaticId;
    #[salsa::interned]
    fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId;
    #[salsa::interned]
    fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
    #[salsa::interned]
    fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId;
}

#[salsa::query_group(DefDatabaseStorage)]
pub trait DefDatabase: InternDatabase + AstDatabase {
    #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
    fn raw_items_with_source_map(
        &self,
        file_id: HirFileId,
    ) -> (Arc<RawItems>, Arc<ImportSourceMap>);

    #[salsa::invoke(RawItems::raw_items_query)]
    fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;

    #[salsa::invoke(CrateDefMap::crate_def_map_query)]
    fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;

    #[salsa::invoke(StructData::struct_data_query)]
    fn struct_data(&self, id: StructOrUnionId) -> Arc<StructData>;

    #[salsa::invoke(EnumData::enum_data_query)]
    fn enum_data(&self, e: EnumId) -> Arc<EnumData>;

    #[salsa::invoke(ImplData::impl_data_query)]
    fn impl_data(&self, e: ImplId) -> Arc<ImplData>;

    #[salsa::invoke(TraitData::trait_data_query)]
    fn trait_data(&self, e: TraitId) -> Arc<TraitData>;

    #[salsa::invoke(TypeAliasData::type_alias_data_query)]
    fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;

    #[salsa::invoke(FunctionData::fn_data_query)]
    fn function_data(&self, func: FunctionId) -> Arc<FunctionData>;

    #[salsa::invoke(ConstData::const_data_query)]
    fn const_data(&self, konst: ConstId) -> Arc<ConstData>;

    #[salsa::invoke(ConstData::static_data_query)]
    fn static_data(&self, konst: StaticId) -> Arc<ConstData>;

    #[salsa::invoke(Body::body_with_source_map_query)]
    fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);

    #[salsa::invoke(Body::body_query)]
    fn body(&self, def: DefWithBodyId) -> Arc<Body>;

    #[salsa::invoke(ExprScopes::expr_scopes_query)]
    fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;

    #[salsa::invoke(GenericParams::generic_params_query)]
    fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;

    #[salsa::invoke(Attrs::attrs_query)]
    fn attrs(&self, def: AttrDefId) -> Attrs;

    #[salsa::invoke(LangItems::module_lang_items_query)]
    fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>;

    #[salsa::invoke(LangItems::crate_lang_items_query)]
    fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;

    #[salsa::invoke(LangItems::lang_item_query)]
    fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;

    // FIXME(https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102)
    // Remove this query completely, in favor of `Attrs::docs` method
    #[salsa::invoke(Documentation::documentation_query)]
    fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
}
<|endoftext|>


<commit_before>//! Simple hierarchical profiler
use once_cell::sync::Lazy;
use std::{
    cell::RefCell,
    collections::{BTreeMap, HashSet},
    io::{stderr, Write},
    sync::{
        atomic::{AtomicBool, Ordering},
        RwLock,
    },
    time::{Duration, Instant},
};

use crate::tree::{Idx, Tree};

/// Filtering syntax
/// env RA_PROFILE=*             // dump everything
/// env RA_PROFILE=foo|bar|baz   // enabled only selected entries
/// env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
pub fn init() {
    let spec = std::env::var("RA_PROFILE").unwrap_or_default();
    init_from(&spec);
}

pub fn init_from(spec: &str) {
    let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) };
    filter.install();
}

pub type Label = &'static str;

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// # Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(label: Label) -> Profiler {
    assert!(!label.is_empty());
    let enabled = PROFILING_ENABLED.load(Ordering::Relaxed)
        && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label));
    let label = if enabled { Some(label) } else { None };
    Profiler { label, detail: None }
}

pub struct Profiler {
    label: Option<Label>,
    detail: Option<String>,
}

impl Profiler {
    pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler {
        if self.label.is_some() {
            self.detail = Some(detail())
        }
        self
    }
}

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { label: Some(label), detail } => {
                PROFILE_STACK.with(|stack| {
                    stack.borrow_mut().pop(label, detail.take());
                });
            }
            Profiler { label: None, .. } => (),
        }
    }
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

#[derive(Default, Clone, Debug)]
struct Filter {
    depth: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
    version: usize,
}

impl Filter {
    fn disabled() -> Filter {
        Filter::default()
    }

    fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() };
        Filter { depth, allowed, longer_than, version: 0 }
    }

    fn install(mut self) {
        PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst);
        let mut old = FILTER.write().unwrap();
        self.version = old.version + 1;
        *old = self;
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    filter: Filter,
    messages: Tree<Message>,
}

#[derive(Default)]
struct Message {
    duration: Duration,
    label: Label,
    detail: Option<String>,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() }
    }

    fn push(&mut self, label: Label) -> bool {
        if self.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > self.filter.version {
                    self.filter = f.clone();
                }
            };
        }
        if self.starts.len() > self.filter.depth {
            return false;
        }
        let allowed = &self.filter.allowed;
        if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
            return false;
        }

        self.starts.push(Instant::now());
        self.messages.start();
        true
    }

    pub fn pop(&mut self, label: Label, detail: Option<String>) {
        let start = self.starts.pop().unwrap();
        let duration = start.elapsed();
        let level = self.starts.len();
        self.messages.finish(Message { duration, label, detail });
        if level == 0 {
            let longer_than = self.filter.longer_than;
            // Convert to millis for comparison to avoid problems with rounding
            // (otherwise we could print `0ms` despite user's `>0` filter when
            // `duration` is just a few nanos).
            if duration.as_millis() > longer_than.as_millis() {
                let stderr = stderr();
                if let Some(root) = self.messages.root() {
                    print(&self.messages, root, 0, longer_than, &mut stderr.lock());
                }
            }
            self.messages.clear();
            assert!(self.starts.is_empty())
        }
    }
}

fn print(
    tree: &Tree<Message>,
    curr: Idx<Message>,
    level: u32,
    longer_than: Duration,
    out: &mut impl Write,
) {
    let current_indent = "    ".repeat(level as usize);
    let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default();
    writeln!(
        out,
        "{}{:5}ms - {}{}",
        current_indent,
        tree[curr].duration.as_millis(),
        tree[curr].label,
        detail,
    )
    .expect("printing profiling info");

    let mut accounted_for = Duration::default();
    let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output.
    for child in tree.children(curr) {
        accounted_for += tree[child].duration;

        if tree[child].duration.as_millis() > longer_than.as_millis() {
            print(tree, child, level + 1, longer_than, out)
        } else {
            let (total_duration, cnt) =
                short_children.entry(tree[child].label).or_insert((Duration::default(), 0));
            *total_duration += tree[child].duration;
            *cnt += 1;
        }
    }

    for (child_msg, (duration, count)) in short_children.iter() {
        let millis = duration.as_millis();
        writeln!(out, "    {}{:5}ms - {} ({} calls)", current_indent, millis, child_msg, count)
            .expect("printing profiling info");
    }

    let unaccounted = tree[curr].duration - accounted_for;
    if tree.children(curr).next().is_some() && unaccounted > longer_than {
        writeln!(out, "    {}{:5}ms - ???", current_indent, unaccounted.as_millis())
            .expect("printing profiling info");
    }
}
<commit_msg>Simplify profiler impl (bubble up Option and shorten code<commit_after>//! Simple hierarchical profiler
use once_cell::sync::Lazy;
use std::{
    cell::RefCell,
    collections::{BTreeMap, HashSet},
    io::{stderr, Write},
    sync::{
        atomic::{AtomicBool, Ordering},
        RwLock,
    },
    time::{Duration, Instant},
};

use crate::tree::{Idx, Tree};

/// Filtering syntax
/// env RA_PROFILE=*             // dump everything
/// env RA_PROFILE=foo|bar|baz   // enabled only selected entries
/// env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
pub fn init() {
    let spec = std::env::var("RA_PROFILE").unwrap_or_default();
    init_from(&spec);
}

pub fn init_from(spec: &str) {
    let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) };
    filter.install();
}

pub type Label = &'static str;

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop.
/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack.
/// In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// # Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(label: Label) -> Profiler {
    assert!(!label.is_empty());

    if PROFILING_ENABLED.load(Ordering::Relaxed)
        && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label))
    {
        Profiler(Some(ProfilerImpl { label, detail: None }))
    } else {
        Profiler(None)
    }
}

pub struct Profiler(Option<ProfilerImpl>);

struct ProfilerImpl {
    label: Label,
    detail: Option<String>,
}

impl Profiler {
    pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler {
        if let Some(profiler) = &mut self.0 {
            profiler.detail = Some(detail())
        }
        self
    }
}

impl Drop for ProfilerImpl {
    fn drop(&mut self) {
        PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take()));
    }
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

#[derive(Default, Clone, Debug)]
struct Filter {
    depth: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
    version: usize,
}

impl Filter {
    fn disabled() -> Filter {
        Filter::default()
    }

    fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() };
        Filter { depth, allowed, longer_than, version: 0 }
    }

    fn install(mut self) {
        PROFILING_ENABLED.store(self.depth > 0, Ordering::SeqCst);
        let mut old = FILTER.write().unwrap();
        self.version = old.version + 1;
        *old = self;
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    filter: Filter,
    messages: Tree<Message>,
}

#[derive(Default)]
struct Message {
    duration: Duration,
    label: Label,
    detail: Option<String>,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() }
    }

    fn push(&mut self, label: Label) -> bool {
        if self.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > self.filter.version {
                    self.filter = f.clone();
                }
            };
        }
        if self.starts.len() > self.filter.depth {
            return false;
        }
        let allowed = &self.filter.allowed;
        if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
            return false;
        }

        self.starts.push(Instant::now());
        self.messages.start();
        true
    }

    pub fn pop(&mut self, label: Label, detail: Option<String>) {
        let start = self.starts.pop().unwrap();
        let duration = start.elapsed();
        self.messages.finish(Message { duration, label, detail });
        if self.starts.is_empty() {
            let longer_than = self.filter.longer_than;
            // Convert to millis for comparison to avoid problems with rounding
            // (otherwise we could print `0ms` despite user's `>0` filter when
            // `duration` is just a few nanos).
            if duration.as_millis() > longer_than.as_millis() {
                if let Some(root) = self.messages.root() {
                    print(&self.messages, root, 0, longer_than, &mut stderr().lock());
                }
            }
            self.messages.clear();
        }
    }
}

fn print(
    tree: &Tree<Message>,
    curr: Idx<Message>,
    level: u32,
    longer_than: Duration,
    out: &mut impl Write,
) {
    let current_indent = "    ".repeat(level as usize);
    let detail = tree[curr].detail.as_ref().map(|it| format!(" @ {}", it)).unwrap_or_default();
    writeln!(
        out,
        "{}{:5}ms - {}{}",
        current_indent,
        tree[curr].duration.as_millis(),
        tree[curr].label,
        detail,
    )
    .expect("printing profiling info");

    let mut accounted_for = Duration::default();
    let mut short_children = BTreeMap::new(); // Use `BTreeMap` to get deterministic output.
    for child in tree.children(curr) {
        accounted_for += tree[child].duration;

        if tree[child].duration.as_millis() > longer_than.as_millis() {
            print(tree, child, level + 1, longer_than, out)
        } else {
            let (total_duration, cnt) =
                short_children.entry(tree[child].label).or_insert((Duration::default(), 0));
            *total_duration += tree[child].duration;
            *cnt += 1;
        }
    }

    for (child_msg, (duration, count)) in short_children.iter() {
        let millis = duration.as_millis();
        writeln!(out, "    {}{:5}ms - {} ({} calls)", current_indent, millis, child_msg, count)
            .expect("printing profiling info");
    }

    let unaccounted = tree[curr].duration - accounted_for;
    if tree.children(curr).next().is_some() && unaccounted > longer_than {
        writeln!(out, "    {}{:5}ms - ???", current_indent, unaccounted.as_millis())
            .expect("printing profiling info");
    }
}
<|endoftext|>


<commit_before>use serde::Deserialize;
use std::process::Command;
use tracing::{event, span, Level};

use crate::error::CmdqError;

#[derive(Debug, Deserialize)]
pub struct Record {
    #[serde(rename = "url")]
    pub url: String,
    #[serde(rename = "title")]
    pub title: String,
}

pub fn execute(url: &str, title: &str) -> Result<(), CmdqError> {
    let span = span!(Level::INFO, "yt-dlp execute", url, title);
    let _enter = span.enter();

    let filename = format!("{} [%(id)s].%(ext)s", clean_title(title));
    validate_filename(&filename)?;

    let args = vec![url.to_string(), "-o".to_string(), filename.clone()];

    let output = Command::new("yt-dlp").args(&args).output().map_err(|err| {
        CmdqError::ProcessExecuteError {
            err: err,
            program: "yt-dlp".to_string(),
            args: args,
        }
    })?;

    if output.status.success() {
        event!(Level::INFO, "execution succeeded");
        Ok(())
    } else {
        let error = CmdqError::ProcessExecuteOutputError {
            stdout: String::from_utf8(output.stdout)
                .map_err(|_err| CmdqError::ProcessExecuteOutputNotUtf8Error)?,
            stderr: String::from_utf8(output.stderr)
                .map_err(|_err| CmdqError::ProcessExecuteOutputNotUtf8Error)?,
        };
        event!(Level::INFO, message = "execution failed", ?error);
        Err(error)
    }
}

fn clean_title(title: &str) -> String {
    title
        .replace("/", "_")
        .replace("\\", "_")
        .replace("+", "_")
        .replace(":", " ")
}

fn validate_filename(filename: &str) -> Result<(), CmdqError> {
    if filename.bytes().len() > 255 {
        Err(CmdqError::FilenameTooLongError {
            filename: filename.to_string(),
        })
    } else {
        Ok(())
    }
}
<commit_msg>cmdq2: Added log<commit_after>use serde::Deserialize;
use std::process::Command;
use tracing::{event, span, Level};

use crate::error::CmdqError;

#[derive(Debug, Deserialize)]
pub struct Record {
    #[serde(rename = "url")]
    pub url: String,
    #[serde(rename = "title")]
    pub title: String,
}

pub fn execute(url: &str, title: &str) -> Result<(), CmdqError> {
    let span = span!(Level::INFO, "yt-dlp execute", url, title);
    let _enter = span.enter();

    let filename = format!("{} [%(id)s].%(ext)s", clean_title(title));
    validate_filename(&filename)?;

    event!(Level::INFO, "executing");
    let args = vec![url.to_string(), "-o".to_string(), filename.clone()];

    let output = Command::new("yt-dlp").args(&args).output().map_err(|err| {
        CmdqError::ProcessExecuteError {
            err: err,
            program: "yt-dlp".to_string(),
            args: args,
        }
    })?;

    if output.status.success() {
        event!(Level::INFO, "execution succeeded");
        Ok(())
    } else {
        let error = CmdqError::ProcessExecuteOutputError {
            stdout: String::from_utf8(output.stdout)
                .map_err(|_err| CmdqError::ProcessExecuteOutputNotUtf8Error)?,
            stderr: String::from_utf8(output.stderr)
                .map_err(|_err| CmdqError::ProcessExecuteOutputNotUtf8Error)?,
        };
        event!(Level::INFO, message = "execution failed", ?error);
        Err(error)
    }
}

fn clean_title(title: &str) -> String {
    title
        .replace("/", "_")
        .replace("\\", "_")
        .replace("+", "_")
        .replace(":", " ")
}

fn validate_filename(filename: &str) -> Result<(), CmdqError> {
    if filename.bytes().len() > 255 {
        Err(CmdqError::FilenameTooLongError {
            filename: filename.to_string(),
        })
    } else {
        Ok(())
    }
}
<|endoftext|>


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

use cpuio;

pub fn halt() {
	loop {
		unsafe {
			asm!("hlt" :::: "volatile");
		}
	}
}

pub fn shutdown() {
	// shutdown, works only on Qemu
	unsafe {
		let mut shutdown_port : cpuio::Port<u8> = cpuio::Port::new(0xf4);
		shutdown_port.write(0x00);
	};

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

#![allow(dead_code)]

use cpuio;
use x86::*;

// feature list 0x00000001 (ebx)
const CPU_FEATURE_FPU : u32 = (1 << 0);
const CPU_FEATURE_PSE : u32 = (1 << 3);
const CPU_FEATURE_MSR : u32 = (1 << 5);
const CPU_FEATURE_PAE : u32 = (1 << 6);
const CPU_FEATURE_APIC : u32 = (1 << 9);
const CPU_FEATURE_SEP : u32 = (1 << 11);
const CPU_FEATURE_PGE : u32 = (1 << 13);
const CPU_FEATURE_PAT : u32 = (1 << 16);
const CPU_FEATURE_PSE36 : u32 = (1 << 17);
const CPU_FEATURE_CLFLUSH : u32 = (1 << 19);
const CPU_FEATURE_MMX : u32 = (1 << 23);
const CPU_FEATURE_FXSR : u32 = (1 << 24);
const CPU_FEATURE_SSE : u32 = (1 << 25);
const CPU_FEATURE_SSE2 : u32 = (1 << 26);

// feature list 0x00000001 (ecx)
const CPU_FEATURE_MWAIT	: u32 = (1 << 3);
const CPU_FEATURE_VMX : u32 = (1 << 5);
const CPU_FEATURE_EST : u32 = (1 << 7);
const CPU_FEATURE_SSE3 : u32 = (1 << 9);
const CPU_FEATURE_FMA : u32 = (1 << 12);
const CPU_FEATURE_DCA : u32 = (1 << 18);
const CPU_FEATURE_SSE4_1 : u32 = (1 << 19);
const CPU_FEATURE_SSE4_2 : u32 = (1 << 20);
const CPU_FEATURE_X2APIC : u32 = (1 << 21);
const CPU_FEATURE_MOVBE	: u32 = (1 << 22);
const CPU_FEATURE_XSAVE	: u32 = (1 << 26);
const CPU_FEATURE_OSXSAVE : u32 = (1 << 27);
const CPU_FEATURE_AVX : u32 = (1 << 28);
const CPU_FEATURE_RDRAND : u32 = (1 << 30);
const CPU_FEATURE_HYPERVISOR : u32 = (1 << 31);

// const.80000001H:EDX feature list
const CPU_FEATURE_SYSCALL : u32 = (1 << 11);
const CPU_FEATURE_NX : u32 = (1 << 20);
const CPU_FEATURE_1GBHP : u32 = (1 << 26);
const CPU_FEATURE_RDTSCP : u32 = (1 << 27);
const CPU_FEATURE_LM : u32 = (1 << 29);

// feature list 0x00000007:0
const CPU_FEATURE_FSGSBASE : u32 = (1 << 0);
const CPU_FEATURE_TSC_ADJUST : u32 = (1 << 1);
const CPU_FEATURE_BMI1	: u32 = (1 << 3);
const CPU_FEATURE_HLE : u32	= (1 << 4);
const CPU_FEATURE_AVX2 : u32 = (1 << 5);
const CPU_FEATURE_SMEP : u32 = (1 << 7);
const CPU_FEATURE_BMI2 : u32 = (1 << 8);
const CPU_FEATURE_ERMS : u32 = (1 << 9);
const CPU_FEATURE_INVPCID : u32 = (1 << 10);
const CPU_FEATURE_RTM : u32 = (1 << 11);
const CPU_FEATURE_CQM : u32 = (1 << 12);
const CPU_FEATURE_MPX : u32 = (1 << 14);
const CPU_FEATURE_AVX512F : u32 = (1 << 16);
const CPU_FEATURE_RDSEED : u32 = (1 << 18);
const CPU_FEATURE_ADX : u32 = (1 << 19);
const CPU_FEATURE_SMAP : u32 = (1 << 20);
const CPU_FEATURE_PCOMMIT : u32 = (1 << 22);
const CPU_FEATURE_CLFLUSHOPT : u32 = (1 << 23);
const CPU_FEATURE_CLWB : u32 = (1 << 24);
const CPU_FEATURE_AVX512PF : u32 = (1 << 26);
const CPU_FEATURE_AVX512ER : u32 = (1 << 27);
const CPU_FEATURE_AVX512CD : u32 = (1 << 28);
const CPU_FEATURE_SHA_NI : u32 = (1 << 29);

// feature list 0x00000006
const CPU_FEATURE_IDA : u32 = (1 << 0);
const CPU_FEATURE_EPB : u32 = (1 << 3);
const CPU_FEATURE_HWP : u32 = (1 << 10);

/*
* EFLAGS bits
*/
const EFLAGS_CF : u32 = (1 <<  0); /* Carry Flag */
const EFLAGS_FIXED : u32 = (1 <<  1); /* Bit 1 - always on */
const EFLAGS_PF	: u32 = (1 <<  2); /* Parity Flag */
const EFLAGS_AF	: u32 = (1 <<  4); /* Auxiliary carry Flag */
const EFLAGS_ZF	: u32 = (1 <<  6); /* Zero Flag */
const EFLAGS_SF	: u32 = (1 <<  7); /* Sign Flag */
const EFLAGS_TF	: u32 = (1 <<  8); /* Trap Flag */
const EFLAGS_IF	: u32 = (1 <<  9); /* Interrupt Flag */
const EFLAGS_DF	: u32 = (1 << 10); /* Direction Flag */
const EFLAGS_OF	: u32 = (1 << 11); /* Overflow Flag */
const EFLAGS_IOPL : u32 = (1 << 12); /* I/O Privilege Level (2 bits) */
const EFLAGS_NT	: u32 = (1 << 14); /* Nested Task */
const EFLAGS_RF	: u32 = (1 << 16); /* Resume Flag */
const EFLAGS_VM	: u32 = (1 << 17); /* Virtual Mode */
const EFLAGS_AC	: u32 = (1 << 18); /* Alignment Check/Access Control */
const EFLAGS_VIF : u32 = (1 << 19); /* Virtual Interrupt Flag */
const EFLAGS_VIP : u32 = (1 << 20); /* Virtual Interrupt Pending */
const EFLAGS_ID : u32 = (1 << 21); /* const detection */

// x86 control registers

/// Protected Mode Enable
const CR0_PE : u64 = (1 << 0);
/// Monitor coprocessor
const CR0_MP : u64 = (1 << 1);
/// Enable FPU emulation
const CR0_EM : u64 = (1 << 2);
/// Task switched
const CR0_TS : u64 = (1 << 3);
/// Extension type of coprocessor
const CR0_ET : u64 = (1 << 4);
/// Enable FPU error reporting
const CR0_NE : u64 = (1 << 5);
/// Enable write protected pages
const CR0_WP : u64 = (1 << 16);
/// Enable alignment checks
const CR0_AM : u64 = (1 << 18);
/// Globally enables/disable write-back caching
const CR0_NW : u64 = (1 << 29);
/// Globally disable memory caching
const CR0_CD : u64 = (1 << 30);
/// Enable paging
const CR0_PG : u64 = (1 << 31);

/// Virtual 8086 Mode Extensions
const CR4_VME: u64 = (1 << 0);
/// Protected-mode Virtual Interrupts
const CR4_PVI : u64 = (1 << 1);
/// Disable Time Stamp Counter register (rdtsc instruction)
const CR4_TSD : u64 = (1 << 2);
/// Enable debug extensions
const CR4_DE : u64 = (1 << 3);
///  Enable hugepage support
const CR4_PSE : u64 = (1 << 4);
/// Enable physical address extension
const CR4_PAE : u64 = (1 << 5);
/// Enable machine check exceptions
const CR4_MCE : u64 = (1 << 6);
/// Enable global pages
const CR4_PGE : u64 = (1 << 7);
/// Enable Performance-Monitoring Counter
const CR4_PCE : u64 = (1 << 8);
/// Enable Operating system support for FXSAVE and FXRSTOR instructions
const CR4_OSFXSR : u64 = (1 << 9);
/// Enable Operating System Support for Unmasked SIMD Floating-Point Exceptions
const CR4_OSXMMEXCPT : u64 = (1 << 10);
/// Enable Virtual Machine Extensions, see Intel VT-x
const CR4_VMXE : u64 = (1 << 13);
/// Enable Safer Mode Extensions, see Trusted Execution Technology (TXT)
const CR4_SMXE : u64 = (1 << 14);
/// Enables the instructions RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE
const CR4_FSGSBASE : u64 = (1 << 16);
/// Enables process-context identifiers
const CR4_PCIDE	: u64 =	(1 << 17);
/// Enable XSAVE and Processor Extended States
const CR4_OSXSAVE : u64 = (1 << 18);
/// Enable Supervisor Mode Execution Protection
const CR4_SMEP : u64 = (1 << 20);
/// Enable Supervisor Mode Access Protection
const CR4_SMAP : u64 = (1 << 21);

// x86-64 specific MSRs

/// APIC register
const MSR_APIC_BASE : u32 = 0x0000001B;
/// extended feature register
const MSR_EFER : u32 = 0xc0000080;
/// legacy mode SYSCALL target
const MSR_STAR : u32 = 0xc0000081;
/// long mode SYSCALL target
const MSR_LSTAR : u32 = 0xc0000082;
/// compat mode SYSCALL target
const MSR_CSTAR : u32 = 0xc0000083;
/// EFLAGS mask for syscall
const MSR_SYSCALL_MASK : u32 = 0xc0000084;
/// 64bit FS base
const MSR_FS_BASE : u32 = 0xc0000100;
/// 64bit GS base
const MSR_GS_BASE : u32 = 0xc0000101;
/// SwapGS GS shadow
const MSR_KERNEL_GS_BASE : u32 = 0xc0000102;

const MSR_XAPIC_ENABLE : u32 = (1 << 11);
const MSR_X2APIC_ENABLE : u32 = (1 << 10);

const MSR_IA32_PLATFORM_ID : u32 = 0x00000017;

const MSR_IA32_PERFCTR0	: u32 = 0x000000c1;
const MSR_IA32_PERFCTR1	: u32 = 0x000000c2;
const MSR_FSB_FREQ : u32 = 0x000000cd;
const MSR_PLATFORM_INFO : u32 = 0x000000ce;

const MSR_IA32_MPERF : u32 = 0x000000e7;
const MSR_IA32_APERF : u32 = 0x000000e8;
const MSR_IA32_MISC_ENABLE : u32 = 0x000001a0;
const MSR_IA32_FEATURE_CONTROL : u32 = 0x0000003a;
const MSR_IA32_ENERGY_PERF_BIAS	: u32 = 0x000001b0;
const MSR_IA32_PERF_STATUS : u32 = 0x00000198;
const MSR_IA32_PERF_CTL : u32 = 0x00000199;
const MSR_IA32_CR_PAT : u32 = 0x00000277;
const MSR_MTRRDEFTYPE : u32 = 0x000002ff;

const MSR_PPERF : u32 = 0x0000064e;
const MSR_PERF_LIMIT_REASONS : u32 = 0x0000064f;
const MSR_PM_ENABLE : u32 = 0x00000770;
const MSR_HWP_CAPABILITIES : u32 = 0x00000771;
const MSR_HWP_REQUEST_PKG : u32 = 0x00000772;
const MSR_HWP_INTERRUPT : u32 = 0x00000773;
const MSR_HWP_REQUEST : u32 = 0x00000774;
const MSR_HWP_STATUS : u32 = 0x00000777;

const MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP : u64 = (1 << 16);
const MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK : u64 = (1 << 20);
const MSR_IA32_MISC_ENABLE_TURBO_DISABLE : u64 = (1 << 38);

const MSR_MTRRFIX64K_00000 : u32 = 0x00000250;
const MSR_MTRRFIX16K_80000 : u32 = 0x00000258;
const MSR_MTRRFIX16K_A0000 : u32 = 0x00000259;
const MSR_MTRRFIX4K_C0000 : u32 = 0x00000268;
const MSR_MTRRFIX4K_C8000 : u32 = 0x00000269;
const MSR_MTRRFIX4K_D0000 : u32 = 0x0000026a;
const MSR_MTRRFIX4K_D8000 : u32 = 0x0000026b;
const MSR_MTRRFIX4K_E0000 : u32 = 0x0000026c;
const MSR_MTRRFIX4K_E8000 : u32 = 0x0000026d;
const MSR_MTRRFIX4K_F0000 : u32 = 0x0000026e;
const MSR_MTRRFIX4K_F8000 : u32 = 0x0000026f;

const MSR_OFFCORE_RSP_0 : u32 = 0x000001a6;
const MSR_OFFCORE_RSP_1 : u32 = 0x000001a7;
const MSR_NHM_TURBO_RATIO_LIMIT : u32 = 0x000001ad;
const MSR_IVT_TURBO_RATIO_LIMIT : u32 = 0x000001ae;
const MSR_TURBO_RATIO_LIMIT : u32 = 0x000001ad;
const MSR_TURBO_RATIO_LIMIT1 : u32 = 0x000001ae;
const MSR_TURBO_RATIO_LIMIT2 : u32 = 0x000001af;

// MSR EFER bits
const EFER_SCE : u32 = (1 << 0);
const EFER_LME : u32 = (1 << 8);
const EFER_LMA : u32 = (1 << 10);
const EFER_NXE : u32 = (1 << 11);
const EFER_SVME : u32 = (1 << 12);
const EFER_LMSLE : u32 = (1 << 13);
const EFER_FFXSR : u32 = (1 << 14);
const EFER_TCE : u32 = (1 << 15);

pub fn halt() {
	loop {
		unsafe {
			asm!("hlt" :::: "volatile");
		}
	}
}

pub fn shutdown() {
	// shutdown, works only on Qemu
	unsafe {
		let mut shutdown_port : cpuio::Port<u8> = cpuio::Port::new(0xf4);
		shutdown_port.write(0x00);
	};

	halt();
}

pub fn cpu_init() {
	let mut _cr0: u64 = unsafe { controlregs::cr0() };

	// be sure that AM, NE and MP is enabled
	_cr0 = _cr0 | CR0_AM;
	_cr0 = _cr0 | CR0_NE;
	_cr0 = _cr0 | CR0_MP;
	// enable cache
	_cr0 = _cr0 & !(CR0_CD|CR0_NW);

	unsafe { controlregs::cr0_write(_cr0) };
}
<|endoftext|>