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

use crate::{
    ChainInfo, FullNode, HealthCheckError, LocalNode, LocalVersion, Node, NodeExt, Swarm,
    Validator, Version,
};
use anyhow::{anyhow, Result};
use diem_config::config::NodeConfig;
use diem_genesis_tool::validator_builder::ValidatorBuilder;
use diem_sdk::{
    crypto::ed25519::Ed25519PrivateKey,
    types::{chain_id::ChainId, AccountKey, LocalAccount, PeerId},
};
use itertools::Itertools;
use std::{
    collections::HashMap,
    convert::TryFrom,
    fs, mem, ops,
    path::{Path, PathBuf},
    sync::Arc,
};
use tempfile::TempDir;

#[derive(Debug)]
pub enum SwarmDirectory {
    Persistent(PathBuf),
    Temporary(TempDir),
}

impl SwarmDirectory {
    pub fn persist(&mut self) {
        match self {
            SwarmDirectory::Persistent(_) => {}
            SwarmDirectory::Temporary(_) => {
                let mut temp = SwarmDirectory::Persistent(PathBuf::new());
                mem::swap(self, &mut temp);
                let _ = mem::replace(self, temp.into_persistent());
            }
        }
    }

    pub fn into_persistent(self) -> Self {
        match self {
            SwarmDirectory::Temporary(tempdir) => SwarmDirectory::Persistent(tempdir.into_path()),
            SwarmDirectory::Persistent(dir) => SwarmDirectory::Persistent(dir),
        }
    }
}

impl ops::Deref for SwarmDirectory {
    type Target = Path;

    fn deref(&self) -> &Self::Target {
        match self {
            SwarmDirectory::Persistent(dir) => dir.deref(),
            SwarmDirectory::Temporary(dir) => dir.path(),
        }
    }
}

impl AsRef<Path> for SwarmDirectory {
    fn as_ref(&self) -> &Path {
        match self {
            SwarmDirectory::Persistent(dir) => dir.as_ref(),
            SwarmDirectory::Temporary(dir) => dir.as_ref(),
        }
    }
}

#[derive(Debug)]
struct ValidatorNetworkAddressEncryptionKey {
    key: diem_sdk::types::network_address::encrypted::Key,
    version: diem_sdk::types::network_address::encrypted::KeyVersion,
}

pub struct LocalSwarmBuilder {
    versions: Arc<HashMap<Version, LocalVersion>>,
    template: NodeConfig,
    number_of_validators: usize,
    dir: Option<PathBuf>,
}

impl LocalSwarmBuilder {
    pub fn new(versions: Arc<HashMap<Version, LocalVersion>>) -> Self {
        Self {
            versions,
            template: NodeConfig::default_for_validator(),
            number_of_validators: 1,
            dir: None,
        }
    }

    pub fn template(mut self, template: NodeConfig) -> Self {
        self.template = template;
        self
    }

    pub fn number_of_validators(mut self, number_of_validators: usize) -> Self {
        self.number_of_validators = number_of_validators;
        self
    }

    pub fn dir<T: AsRef<Path>>(mut self, dir: T) -> Self {
        self.dir = Some(dir.as_ref().into());
        self
    }

    pub fn build(self) -> Result<LocalSwarm> {
        let dir = if let Some(dir) = self.dir {
            if dir.exists() {
                fs::remove_dir_all(&dir)?;
            }
            fs::create_dir_all(&dir)?;
            SwarmDirectory::Persistent(dir)
        } else {
            SwarmDirectory::Temporary(TempDir::new()?)
        };

        let (root_keys, validators) = ValidatorBuilder::new(
            &dir,
            diem_framework_releases::current_module_blobs().to_vec(),
        )
        .num_validators(self.number_of_validators)
        .template(self.template)
        .build()?;

        // Get the latest version to start the nodes with
        let version = self
            .versions
            .iter()
            .max_by(|v1, v2| v1.0.cmp(&v2.0))
            .unwrap()
            .1;

        let validators = validators
            .into_iter()
            .map(|v| {
                let node = LocalNode::new(version.to_owned(), v.name, v.directory)?;
                Ok((node.peer_id(), node))
            })
            .collect::<Result<HashMap<_, _>>>()?;

        let validator_network_address_encryption_key = ValidatorNetworkAddressEncryptionKey {
            key: root_keys.validator_network_address_encryption_key,
            version: root_keys.validator_network_address_encryption_key_version,
        };

        let root_account = LocalAccount::new(
            diem_sdk::types::account_config::diem_root_address(),
            AccountKey::from_private_key(root_keys.root_key),
            1,
        );

        // Designated dealer account is built to have the same private key as the TC account
        let designated_dealer_account = LocalAccount::new(
            diem_sdk::types::account_config::testnet_dd_account_address(),
            AccountKey::from_private_key(
                Ed25519PrivateKey::try_from(root_keys.treasury_compliance_key.to_bytes().as_ref())
                    .unwrap(),
            ),
            0,
        );

        let treasury_compliance_account = LocalAccount::new(
            diem_sdk::types::account_config::treasury_compliance_account_address(),
            AccountKey::from_private_key(root_keys.treasury_compliance_key),
            0,
        );

        Ok(LocalSwarm {
            versions: self.versions,
            validators,
            full_nodes: HashMap::new(),
            dir,
            validator_network_address_encryption_key,
            root_account,
            treasury_compliance_account,
            designated_dealer_account,
            chain_id: ChainId::test(),
        })
    }
}

#[derive(Debug)]
pub struct LocalSwarm {
    versions: Arc<HashMap<Version, LocalVersion>>,
    validators: HashMap<PeerId, LocalNode>,
    full_nodes: HashMap<PeerId, LocalNode>,
    dir: SwarmDirectory,
    validator_network_address_encryption_key: ValidatorNetworkAddressEncryptionKey,
    root_account: LocalAccount,
    treasury_compliance_account: LocalAccount,
    designated_dealer_account: LocalAccount,
    chain_id: ChainId,
}

impl LocalSwarm {
    pub fn builder(versions: Arc<HashMap<Version, LocalVersion>>) -> LocalSwarmBuilder {
        LocalSwarmBuilder::new(versions)
    }

    pub fn launch(&mut self) -> Result<()> {
        // Start all the validators
        for validator in self.validators.values_mut() {
            validator.start()?;
        }

        // Wait for all of them to startup
        self.wait_for_startup()?;
        self.wait_for_connectivity()?;
        self.liveness_check()?;

        Ok(())
    }

    fn wait_for_startup(&mut self) -> Result<()> {
        let num_attempts = 10;
        let mut done = vec![false; self.validators.len()];
        for i in 0..num_attempts {
            println!("Wait for startup attempt: {} of {}", i, num_attempts);
            for (node, done) in self.validators.values_mut().zip(done.iter_mut()) {
                if *done {
                    continue;
                }
                match node.health_check() {
                    Ok(()) => *done = true,

                    Err(HealthCheckError::Unknown(e)) => {
                        return Err(anyhow!("Diem node '{}' is not running: {}", node.name(), e));
                    }
                    Err(HealthCheckError::NotRunning) => {
                        return Err(anyhow!("Diem node '{}' is not running", node.name()));
                    }
                    Err(HealthCheckError::RpcFailure(e)) => {
                        println!("rpc error: {}", e);
                        continue;
                    }
                }
            }

            // Check if all the nodes have been successfully launched
            if done.iter().all(|status| *status) {
                return Ok(());
            }

            ::std::thread::sleep(::std::time::Duration::from_millis(1000));
        }

        Err(anyhow!("Launching Swarm timed out"))
    }

    fn wait_for_connectivity(&self) -> Result<()> {
        let expected_peers = self.validators.len().saturating_sub(1);

        let num_attempts = 60;
        for i in 0..num_attempts {
            println!("Wait for connectivity attempt: {}", i);

            if self
                .validators
                .values()
                .map(|node| Validator::check_connectivity(node, expected_peers))
                .collect::<Result<Vec<_>>>()?
                .into_iter()
                .all(|b| b)
            {
                return Ok(());
            }

            ::std::thread::sleep(::std::time::Duration::from_millis(1000));
        }

        Err(anyhow!("Waiting for connectivity timed out"))
    }

    fn liveness_check(&self) -> Result<()> {
        let num_attempts = 60;
        for i in 0..num_attempts {
            println!("Wait for liveness check attempt: {}", i);

            if self
                .validators
                .values()
                .map(|node| node.liveness_check(10))
                .collect_vec()
                .into_iter()
                .all(|b| matches!(b, Ok(..)))
            {
                return Ok(());
            }

            ::std::thread::sleep(::std::time::Duration::from_millis(1000));
        }

        Err(anyhow!("Liveness check timed out"))
    }
}

impl Swarm for LocalSwarm {
    fn health_check(&mut self) -> Result<()> {
        todo!()
    }

    fn validators<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn Validator> + 'a> {
        Box::new(self.validators.values().map(|v| v as &'a dyn Validator))
    }

    fn validators_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut dyn Validator> + 'a> {
        Box::new(
            self.validators
                .values_mut()
                .map(|v| v as &'a mut dyn Validator),
        )
    }

    fn validator(&self, id: PeerId) -> Option<&dyn Validator> {
        self.validators.get(&id).map(|v| v as &dyn Validator)
    }

    fn validator_mut(&mut self, id: PeerId) -> Option<&mut dyn Validator> {
        self.validators
            .get_mut(&id)
            .map(|v| v as &mut dyn Validator)
    }

    fn upgrade_validator(&mut self, id: PeerId, version: &Version) -> Result<()> {
        let version = self
            .versions
            .get(&version)
            .cloned()
            .ok_or_else(|| anyhow!("Invalid version: {:?}", version))?;
        let validator = self
            .validators
            .get_mut(&id)
            .ok_or_else(|| anyhow!("Invalid id: {}", id))?;
        validator.upgrade(version)
    }

    fn full_nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn FullNode> + 'a> {
        Box::new(self.full_nodes.values().map(|v| v as &'a dyn FullNode))
    }

    fn full_nodes_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut dyn FullNode> + 'a> {
        Box::new(
            self.full_nodes
                .values_mut()
                .map(|v| v as &'a mut dyn FullNode),
        )
    }

    fn full_node(&self, id: PeerId) -> Option<&dyn FullNode> {
        self.full_nodes.get(&id).map(|v| v as &dyn FullNode)
    }

    fn full_node_mut(&mut self, id: PeerId) -> Option<&mut dyn FullNode> {
        self.full_nodes.get_mut(&id).map(|v| v as &mut dyn FullNode)
    }

    fn add_validator(&mut self, _id: PeerId) -> Result<PeerId> {
        todo!()
    }

    fn remove_validator(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn add_full_node(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn remove_full_node(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        Box::new(self.versions.keys().cloned())
    }

    fn chain_info(&mut self) -> ChainInfo<'_> {
        ChainInfo::new(
            &mut self.root_account,
            &mut self.treasury_compliance_account,
            &mut self.designated_dealer_account,
            self.validators
                .values()
                .map(|v| v.json_rpc_endpoint().to_string())
                .next()
                .unwrap(),
            self.chain_id,
        )
    }
}
<commit_msg>forge: use the SwarmExt connectivity and liveness checks for LocalSwarm<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    ChainInfo, FullNode, HealthCheckError, LocalNode, LocalVersion, Node, Swarm, SwarmExt,
    Validator, Version,
};
use anyhow::{anyhow, Result};
use diem_config::config::NodeConfig;
use diem_genesis_tool::validator_builder::ValidatorBuilder;
use diem_sdk::{
    crypto::ed25519::Ed25519PrivateKey,
    types::{chain_id::ChainId, AccountKey, LocalAccount, PeerId},
};
use std::{
    collections::HashMap,
    convert::TryFrom,
    fs, mem, ops,
    path::{Path, PathBuf},
    sync::Arc,
    time::{Duration, Instant},
};
use tempfile::TempDir;

#[derive(Debug)]
pub enum SwarmDirectory {
    Persistent(PathBuf),
    Temporary(TempDir),
}

impl SwarmDirectory {
    pub fn persist(&mut self) {
        match self {
            SwarmDirectory::Persistent(_) => {}
            SwarmDirectory::Temporary(_) => {
                let mut temp = SwarmDirectory::Persistent(PathBuf::new());
                mem::swap(self, &mut temp);
                let _ = mem::replace(self, temp.into_persistent());
            }
        }
    }

    pub fn into_persistent(self) -> Self {
        match self {
            SwarmDirectory::Temporary(tempdir) => SwarmDirectory::Persistent(tempdir.into_path()),
            SwarmDirectory::Persistent(dir) => SwarmDirectory::Persistent(dir),
        }
    }
}

impl ops::Deref for SwarmDirectory {
    type Target = Path;

    fn deref(&self) -> &Self::Target {
        match self {
            SwarmDirectory::Persistent(dir) => dir.deref(),
            SwarmDirectory::Temporary(dir) => dir.path(),
        }
    }
}

impl AsRef<Path> for SwarmDirectory {
    fn as_ref(&self) -> &Path {
        match self {
            SwarmDirectory::Persistent(dir) => dir.as_ref(),
            SwarmDirectory::Temporary(dir) => dir.as_ref(),
        }
    }
}

#[derive(Debug)]
struct ValidatorNetworkAddressEncryptionKey {
    key: diem_sdk::types::network_address::encrypted::Key,
    version: diem_sdk::types::network_address::encrypted::KeyVersion,
}

pub struct LocalSwarmBuilder {
    versions: Arc<HashMap<Version, LocalVersion>>,
    template: NodeConfig,
    number_of_validators: usize,
    dir: Option<PathBuf>,
}

impl LocalSwarmBuilder {
    pub fn new(versions: Arc<HashMap<Version, LocalVersion>>) -> Self {
        Self {
            versions,
            template: NodeConfig::default_for_validator(),
            number_of_validators: 1,
            dir: None,
        }
    }

    pub fn template(mut self, template: NodeConfig) -> Self {
        self.template = template;
        self
    }

    pub fn number_of_validators(mut self, number_of_validators: usize) -> Self {
        self.number_of_validators = number_of_validators;
        self
    }

    pub fn dir<T: AsRef<Path>>(mut self, dir: T) -> Self {
        self.dir = Some(dir.as_ref().into());
        self
    }

    pub fn build(self) -> Result<LocalSwarm> {
        let dir = if let Some(dir) = self.dir {
            if dir.exists() {
                fs::remove_dir_all(&dir)?;
            }
            fs::create_dir_all(&dir)?;
            SwarmDirectory::Persistent(dir)
        } else {
            SwarmDirectory::Temporary(TempDir::new()?)
        };

        let (root_keys, validators) = ValidatorBuilder::new(
            &dir,
            diem_framework_releases::current_module_blobs().to_vec(),
        )
        .num_validators(self.number_of_validators)
        .template(self.template)
        .build()?;

        // Get the latest version to start the nodes with
        let version = self
            .versions
            .iter()
            .max_by(|v1, v2| v1.0.cmp(&v2.0))
            .unwrap()
            .1;

        let validators = validators
            .into_iter()
            .map(|v| {
                let node = LocalNode::new(version.to_owned(), v.name, v.directory)?;
                Ok((node.peer_id(), node))
            })
            .collect::<Result<HashMap<_, _>>>()?;

        let validator_network_address_encryption_key = ValidatorNetworkAddressEncryptionKey {
            key: root_keys.validator_network_address_encryption_key,
            version: root_keys.validator_network_address_encryption_key_version,
        };

        let root_account = LocalAccount::new(
            diem_sdk::types::account_config::diem_root_address(),
            AccountKey::from_private_key(root_keys.root_key),
            1,
        );

        // Designated dealer account is built to have the same private key as the TC account
        let designated_dealer_account = LocalAccount::new(
            diem_sdk::types::account_config::testnet_dd_account_address(),
            AccountKey::from_private_key(
                Ed25519PrivateKey::try_from(root_keys.treasury_compliance_key.to_bytes().as_ref())
                    .unwrap(),
            ),
            0,
        );

        let treasury_compliance_account = LocalAccount::new(
            diem_sdk::types::account_config::treasury_compliance_account_address(),
            AccountKey::from_private_key(root_keys.treasury_compliance_key),
            0,
        );

        Ok(LocalSwarm {
            versions: self.versions,
            validators,
            full_nodes: HashMap::new(),
            dir,
            validator_network_address_encryption_key,
            root_account,
            treasury_compliance_account,
            designated_dealer_account,
            chain_id: ChainId::test(),
        })
    }
}

#[derive(Debug)]
pub struct LocalSwarm {
    versions: Arc<HashMap<Version, LocalVersion>>,
    validators: HashMap<PeerId, LocalNode>,
    full_nodes: HashMap<PeerId, LocalNode>,
    dir: SwarmDirectory,
    validator_network_address_encryption_key: ValidatorNetworkAddressEncryptionKey,
    root_account: LocalAccount,
    treasury_compliance_account: LocalAccount,
    designated_dealer_account: LocalAccount,
    chain_id: ChainId,
}

impl LocalSwarm {
    pub fn builder(versions: Arc<HashMap<Version, LocalVersion>>) -> LocalSwarmBuilder {
        LocalSwarmBuilder::new(versions)
    }

    pub fn launch(&mut self) -> Result<()> {
        // Start all the validators
        for validator in self.validators.values_mut() {
            validator.start()?;
        }

        // Wait for all of them to startup
        let deadline = Instant::now() + Duration::from_secs(60);
        self.wait_for_startup()?;
        self.wait_for_connectivity(deadline)?;
        self.liveness_check(deadline)?;

        Ok(())
    }

    fn wait_for_startup(&mut self) -> Result<()> {
        let num_attempts = 10;
        let mut done = vec![false; self.validators.len()];
        for i in 0..num_attempts {
            println!("Wait for startup attempt: {} of {}", i, num_attempts);
            for (node, done) in self.validators.values_mut().zip(done.iter_mut()) {
                if *done {
                    continue;
                }
                match node.health_check() {
                    Ok(()) => *done = true,

                    Err(HealthCheckError::Unknown(e)) => {
                        return Err(anyhow!("Diem node '{}' is not running: {}", node.name(), e));
                    }
                    Err(HealthCheckError::NotRunning) => {
                        return Err(anyhow!("Diem node '{}' is not running", node.name()));
                    }
                    Err(HealthCheckError::RpcFailure(e)) => {
                        println!("rpc error: {}", e);
                        continue;
                    }
                }
            }

            // Check if all the nodes have been successfully launched
            if done.iter().all(|status| *status) {
                return Ok(());
            }

            ::std::thread::sleep(::std::time::Duration::from_millis(1000));
        }

        Err(anyhow!("Launching Swarm timed out"))
    }
}

impl Swarm for LocalSwarm {
    fn health_check(&mut self) -> Result<()> {
        todo!()
    }

    fn validators<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn Validator> + 'a> {
        Box::new(self.validators.values().map(|v| v as &'a dyn Validator))
    }

    fn validators_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut dyn Validator> + 'a> {
        Box::new(
            self.validators
                .values_mut()
                .map(|v| v as &'a mut dyn Validator),
        )
    }

    fn validator(&self, id: PeerId) -> Option<&dyn Validator> {
        self.validators.get(&id).map(|v| v as &dyn Validator)
    }

    fn validator_mut(&mut self, id: PeerId) -> Option<&mut dyn Validator> {
        self.validators
            .get_mut(&id)
            .map(|v| v as &mut dyn Validator)
    }

    fn upgrade_validator(&mut self, id: PeerId, version: &Version) -> Result<()> {
        let version = self
            .versions
            .get(&version)
            .cloned()
            .ok_or_else(|| anyhow!("Invalid version: {:?}", version))?;
        let validator = self
            .validators
            .get_mut(&id)
            .ok_or_else(|| anyhow!("Invalid id: {}", id))?;
        validator.upgrade(version)
    }

    fn full_nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn FullNode> + 'a> {
        Box::new(self.full_nodes.values().map(|v| v as &'a dyn FullNode))
    }

    fn full_nodes_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut dyn FullNode> + 'a> {
        Box::new(
            self.full_nodes
                .values_mut()
                .map(|v| v as &'a mut dyn FullNode),
        )
    }

    fn full_node(&self, id: PeerId) -> Option<&dyn FullNode> {
        self.full_nodes.get(&id).map(|v| v as &dyn FullNode)
    }

    fn full_node_mut(&mut self, id: PeerId) -> Option<&mut dyn FullNode> {
        self.full_nodes.get_mut(&id).map(|v| v as &mut dyn FullNode)
    }

    fn add_validator(&mut self, _id: PeerId) -> Result<PeerId> {
        todo!()
    }

    fn remove_validator(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn add_full_node(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn remove_full_node(&mut self, _id: PeerId) -> Result<()> {
        todo!()
    }

    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        Box::new(self.versions.keys().cloned())
    }

    fn chain_info(&mut self) -> ChainInfo<'_> {
        ChainInfo::new(
            &mut self.root_account,
            &mut self.treasury_compliance_account,
            &mut self.designated_dealer_account,
            self.validators
                .values()
                .map(|v| v.json_rpc_endpoint().to_string())
                .next()
                .unwrap(),
            self.chain_id,
        )
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;<commit_msg>Add skeleton version of demux device.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use libc::{c_ulong};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult,DeviceError};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Frontend> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn stop(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn get_system_time_counter(&self) -> DeviceResult<SystemTimeCounter> {
        unimplemented!();
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        unimplemented!();
    }

    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        unimplemented!();
    }

    pub fn set_source(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn remove_pid(&selfm, pid: u16) -> DeviceResult<()> {
        unimplemented!();
    }
}<|endoftext|>


<commit_before>use std::env::args;

fn fuel_required(mass: i32) -> i32 { (mass / 3) - 2 }

fn main() {
    let modules = args().skip(1).map(|arg| {
        arg.parse().unwrap()
    });

    let total_fuel: i32 = modules.map(|module| { fuel_required(module) }).sum();

    println!("{}", total_fuel);
}
<commit_msg>Add part 2<commit_after>use std::env::args;

fn fuel_required(mass: i32) -> i32 { (mass / 3) - 2 }

fn full_fuel_required(mass: i32) -> i32 {
    let mut fuel = fuel_required(mass);
    let mut new_fuel = fuel_required(fuel);
    while new_fuel > 0 {
        fuel += new_fuel;
        new_fuel = fuel_required(new_fuel);
    }

    fuel
}

fn main() {
    let modules: Vec<i32> = args().skip(1).map(|arg| {
        arg.parse().unwrap()
    }).collect();

    let total_fuel: i32 = modules.iter().map(|module| { fuel_required(*module) }).sum();
    let full_total_fuel: i32 = modules.iter().map(|module| { full_fuel_required(*module) }).sum();

    println!("{}\n{}", total_fuel, full_total_fuel);
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

/// An error type for failures of converting timestamps to microseconds.
#[derive(Clone, Debug)]
pub enum MicrosError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl std::fmt::Display for MicrosError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for MicrosError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for MicrosError {

    fn from(error: std::time::SystemTimeError) -> MicrosError {
        MicrosError::Epoch(error)
    }
}

impl From<std::num::TryFromIntError> for MicrosError {

    fn from(error: std::num::TryFromIntError) -> MicrosError {
        MicrosError::Overflow(error)
    }
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, MicrosError> {
    let time_micros = time.duration_since(std::time::UNIX_EPOCH)?.as_micros();
    Ok(std::convert::TryInto::try_into(time_micros)?)
}
<commit_msg>Add an iterator conversion for attributed dicts.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

impl<K, V> std::iter::FromIterator<(K, V)> for AttributedDict
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let pair = |(key, value)| KeyValue::pair(key, value);

        AttributedDict {
            dat: iter.into_iter().map(pair).collect(),
        }
    }
}

/// An error type for failures of converting timestamps to microseconds.
#[derive(Clone, Debug)]
pub enum MicrosError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl std::fmt::Display for MicrosError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for MicrosError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for MicrosError {

    fn from(error: std::time::SystemTimeError) -> MicrosError {
        MicrosError::Epoch(error)
    }
}

impl From<std::num::TryFromIntError> for MicrosError {

    fn from(error: std::num::TryFromIntError) -> MicrosError {
        MicrosError::Overflow(error)
    }
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, MicrosError> {
    let time_micros = time.duration_since(std::time::UNIX_EPOCH)?.as_micros();
    Ok(std::convert::TryInto::try_into(time_micros)?)
}
<|endoftext|>


<commit_before>//! Exceptions
//!
//! All the exceptions prefixed with an underscore (`_`) can be overridden by
//! the top crate. Check out
//! [this example](../examples/override_exception/index.html).

use cortex_m::{self, Handler};
#[cfg(feature = "default-exception-handler")]
use cortex_m::StackFrame;

/// Kind of exception
#[derive(Debug)]
pub enum Exception {
    /// i.e. currently not servicing an exception
    ThreadMode,
    /// Non-maskable interrupt.
    Nmi,
    /// All class of fault.
    HardFault,
    /// Memory management.
    MemoryManagementFault,
    /// Pre-fetch fault, memory access fault.
    BusFault,
    /// Undefined instruction or illegal state.
    UsageFault,
    /// System service call via SWI instruction
    SVCall,
    /// Pendable request for system service
    PendSV,
    /// System tick timer
    Systick,
    /// An interrupt
    Interrupt(u8),
    // Unreachable variant
    #[doc(hidden)]
    Reserved,
}

impl Exception {
    /// Returns the exception that's currently being serviced
    pub fn current() -> Exception {
        match cortex_m::peripheral::scb().icsr.read() as u8 {
            0 => Exception::ThreadMode,
            2 => Exception::Nmi,
            3 => Exception::HardFault,
            4 => Exception::MemoryManagementFault,
            5 => Exception::BusFault,
            6 => Exception::UsageFault,
            11 => Exception::SVCall,
            14 => Exception::PendSV,
            15 => Exception::Systick,
            n if n >= 16 => Exception::Interrupt(n - 16),
            _ => Exception::Reserved,

        }
    }
}

#[cfg(all(target_arch = "arm", feature = "default-exception-handler"))]
#[doc(hidden)]
#[naked]
#[no_mangle]
pub unsafe extern "C" fn _default_exception_handler() {
    use core::intrinsics;

    // NOTE need asm!, #[naked] and unreachable() to avoid modifying the stack
    // pointer (MSP)
    asm!("mrs r0, MSP
          ldr r1, [r0, #20]
          b $0" :: "i"(deh as extern "C" fn(&StackFrame) -> !) :: "volatile");

    intrinsics::unreachable();
}

#[cfg(feature = "default-exception-handler")]
#[doc(hidden)]
extern "C" fn deh(sf: &StackFrame) -> ! {
    iprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), sf.pc);

    unsafe {
        bkpt!();
    }

    loop {}
}

/// List of all the exceptions minus the reset handler as allocated in the
/// vector table.
///
/// `None` indicates that the spot is RESERVED.
#[doc(hidden)]
#[export_name = "_EXCEPTIONS"]
pub static EXCEPTIONS: [Option<Handler>; 14] = [Some(_nmi),
                                                Some(_hard_fault),
                                                Some(_memmanage_fault),
                                                Some(_bus_fault),
                                                Some(_usage_fault),
                                                None,
                                                None,
                                                None,
                                                None,
                                                Some(_svcall),
                                                None,
                                                None,
                                                Some(_pendsv),
                                                Some(_systick)];

extern "C" {
    /// Non-maskable interrupt.
    pub fn _nmi();
    /// All class of fault.
    pub fn _hard_fault();
    /// Memory management.
    pub fn _memmanage_fault();
    /// Pre-fetch fault, memory access fault.
    pub fn _bus_fault();
    /// Undefined instruction or illegal state.
    pub fn _usage_fault();
    /// System service call via SWI instruction
    pub fn _svcall();
    /// Pendable request for system service
    pub fn _pendsv();
    /// System tick timer
    pub fn _systick();
}

/// Reset handler
#[doc(hidden)]
#[export_name = "_reset"]
pub unsafe extern "C" fn reset() -> ! {
    #[cfg(feature = "default-init")]
    use ::_init;

    extern "C" {
        static _ebss: u32;
        static _edata: u32;
        static _sidata: u32;
        static mut _sbss: u32;
        static mut _sdata: u32;
    }

    extern "Rust" {
        #[cfg(not(feature = "default-init"))]
        fn _init();

        // `main`, the entry point of the user program
        // NOTE the right signature of `main` is `fn() -> !`. But the user might
        // get that wrong so let's err on the side of caution and install a
        // safety net. (See below)
        fn main();
    }

    match () {
        #[cfg(feature = "static-ram")]
        () => {
            if &_sbss as *const _ as usize != &_ebss as *const _ as usize {
                ::r0::zero_bss(&mut _sbss, &_ebss);
            }

            if &_sdata as *const _ as usize != &_edata as *const _ as usize {
                ::r0::init_data(&mut _sdata, &_edata, &_sidata);
            }
        }
        #[cfg(not(feature = "static-ram"))]
        () => {}
    }

    _init();

    main();

    // safety net in case `main` returns
    panic!("returned from `main`!")
}
<commit_msg>fix warning on x86<commit_after>//! Exceptions
//!
//! All the exceptions prefixed with an underscore (`_`) can be overridden by
//! the top crate. Check out
//! [this example](../examples/override_exception/index.html).

use cortex_m::{self, Handler};
#[cfg(feature = "default-exception-handler")]
use cortex_m::StackFrame;

/// Kind of exception
#[derive(Debug)]
pub enum Exception {
    /// i.e. currently not servicing an exception
    ThreadMode,
    /// Non-maskable interrupt.
    Nmi,
    /// All class of fault.
    HardFault,
    /// Memory management.
    MemoryManagementFault,
    /// Pre-fetch fault, memory access fault.
    BusFault,
    /// Undefined instruction or illegal state.
    UsageFault,
    /// System service call via SWI instruction
    SVCall,
    /// Pendable request for system service
    PendSV,
    /// System tick timer
    Systick,
    /// An interrupt
    Interrupt(u8),
    // Unreachable variant
    #[doc(hidden)]
    Reserved,
}

impl Exception {
    /// Returns the exception that's currently being serviced
    pub fn current() -> Exception {
        match cortex_m::peripheral::scb().icsr.read() as u8 {
            0 => Exception::ThreadMode,
            2 => Exception::Nmi,
            3 => Exception::HardFault,
            4 => Exception::MemoryManagementFault,
            5 => Exception::BusFault,
            6 => Exception::UsageFault,
            11 => Exception::SVCall,
            14 => Exception::PendSV,
            15 => Exception::Systick,
            n if n >= 16 => Exception::Interrupt(n - 16),
            _ => Exception::Reserved,

        }
    }
}

#[cfg(all(target_arch = "arm", feature = "default-exception-handler"))]
#[doc(hidden)]
#[naked]
#[no_mangle]
pub unsafe extern "C" fn _default_exception_handler() {
    use core::intrinsics;

    // NOTE need asm!, #[naked] and unreachable() to avoid modifying the stack
    // pointer (MSP)
    asm!("mrs r0, MSP
          ldr r1, [r0, #20]
          b $0" :: "i"(deh as extern "C" fn(&StackFrame) -> !) :: "volatile");

    intrinsics::unreachable();
}

#[cfg(all(target_arch = "arm", feature = "default-exception-handler"))]
#[doc(hidden)]
extern "C" fn deh(sf: &StackFrame) -> ! {
    iprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), sf.pc);

    unsafe {
        bkpt!();
    }

    loop {}
}

/// List of all the exceptions minus the reset handler as allocated in the
/// vector table.
///
/// `None` indicates that the spot is RESERVED.
#[doc(hidden)]
#[export_name = "_EXCEPTIONS"]
pub static EXCEPTIONS: [Option<Handler>; 14] = [Some(_nmi),
                                                Some(_hard_fault),
                                                Some(_memmanage_fault),
                                                Some(_bus_fault),
                                                Some(_usage_fault),
                                                None,
                                                None,
                                                None,
                                                None,
                                                Some(_svcall),
                                                None,
                                                None,
                                                Some(_pendsv),
                                                Some(_systick)];

extern "C" {
    /// Non-maskable interrupt.
    pub fn _nmi();
    /// All class of fault.
    pub fn _hard_fault();
    /// Memory management.
    pub fn _memmanage_fault();
    /// Pre-fetch fault, memory access fault.
    pub fn _bus_fault();
    /// Undefined instruction or illegal state.
    pub fn _usage_fault();
    /// System service call via SWI instruction
    pub fn _svcall();
    /// Pendable request for system service
    pub fn _pendsv();
    /// System tick timer
    pub fn _systick();
}

/// Reset handler
#[doc(hidden)]
#[export_name = "_reset"]
pub unsafe extern "C" fn reset() -> ! {
    #[cfg(feature = "default-init")]
    use ::_init;

    extern "C" {
        static _ebss: u32;
        static _edata: u32;
        static _sidata: u32;
        static mut _sbss: u32;
        static mut _sdata: u32;
    }

    extern "Rust" {
        #[cfg(not(feature = "default-init"))]
        fn _init();

        // `main`, the entry point of the user program
        // NOTE the right signature of `main` is `fn() -> !`. But the user might
        // get that wrong so let's err on the side of caution and install a
        // safety net. (See below)
        fn main();
    }

    match () {
        #[cfg(feature = "static-ram")]
        () => {
            if &_sbss as *const _ as usize != &_ebss as *const _ as usize {
                ::r0::zero_bss(&mut _sbss, &_ebss);
            }

            if &_sdata as *const _ as usize != &_edata as *const _ as usize {
                ::r0::init_data(&mut _sdata, &_edata, &_sidata);
            }
        }
        #[cfg(not(feature = "static-ram"))]
        () => {}
    }

    _init();

    main();

    // safety net in case `main` returns
    panic!("returned from `main`!")
}
<|endoftext|>


<commit_before>extern crate protoc;

use std::ffi::OsString;
use std::io::Result;
use std::path::PathBuf;

fn main() -> Result<()> {
    let exe_suffix = if cfg!(windows) {
        ".exe"
    } else if cfg!(unix) {
        ""
    } else {
        panic!("unknown OS")
    };

    // TODO: https://github.com/rust-lang/cargo/issues/4316

    let gen_rust_binary = format!("../../target/debug/protoc-gen-rust{}", exe_suffix);
    let gen_rust_binary = PathBuf::from(gen_rust_binary).canonicalize()?;

    assert!(gen_rust_binary.is_file(), "{:?}", gen_rust_binary);

    let mut gen_rust_plugin = OsString::from("protoc-gen-rust=");
    gen_rust_plugin.push(gen_rust_binary);

    protoc::Args::new()
        .lang("rust")
        .out_dir("src")
        .plugin(gen_rust_plugin)
        .input("src/data.proto")
        .run()?;

    Ok(())
}
<commit_msg>Follow renames<commit_after>extern crate protoc;

use std::ffi::OsString;
use std::io::Result;
use std::path::PathBuf;

fn main() -> Result<()> {
    let exe_suffix = if cfg!(windows) {
        ".exe"
    } else if cfg!(unix) {
        ""
    } else {
        panic!("unknown OS")
    };

    // TODO: https://github.com/rust-lang/cargo/issues/4316

    let gen_rust_binary = format!("../../target/debug/protoc-gen-rust{}", exe_suffix);
    let gen_rust_binary = PathBuf::from(gen_rust_binary).canonicalize()?;

    assert!(gen_rust_binary.is_file(), "{:?}", gen_rust_binary);

    let mut gen_rust_plugin = OsString::from("protoc-gen-rust=");
    gen_rust_plugin.push(gen_rust_binary);

    protoc::ProtocLangOut::new()
        .lang("rust")
        .out_dir("src")
        .plugin(gen_rust_plugin)
        .input("src/data.proto")
        .run()?;

    Ok(())
}
<|endoftext|>


<commit_before>use std::os::raw::{c_char, c_void, c_int};
use std::mem;
use std::default::Default;
use std::fmt;

use ffi;

pub type PmDeviceId = c_int;
pub type PortMidiStream = c_void;
pub type PmMessage = c_int;
pub type PmTimestamp = u32;
pub const PM_NO_DEVICE: PmDeviceId = -1;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct PmEvent {
    pub message: PmMessage,
    pub timestamp: PmTimestamp,
}
impl Default for PmEvent {
    fn default() -> Self {
        PmEvent {
            message: 0,
            timestamp: 0,
        }
    }
}

#[repr(C)]
pub struct PmDeviceInfo {
    /// this internal structure version
    pub struct_version: c_int,
    /// underlying MIDI API, e.g. MMSystem or DirectX
    pub interf: *const c_char,
    /// device name, e.g. USB MidiSport 1x1
    pub name: *const c_char,
    /// true iff input is available
    pub input: c_int,
    /// true iff output is available
    pub output: c_int,
    /// used by generic PortMidi code to do error checking on arguments
    pub opened: c_int,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum PmError {
    /// "no error" return that also indicates data available
    PmNoError = 0,
    /// "no error" return that also indicates data available
    PmGotData = 1,
    PmHostError = -10000,
    /// out of range or
    /// output device when input is requested or
    /// input device when output is requested or
    /// device is already opened
    PmInvalidDeviceId = -9999,
    PmInsufficientMemory = -9998,
    PmBufferTooSmall = -9997,
    PmBufferOverflow = -9996,
    /// PortMidiStream parameter is NULL or
    /// stream is not opened or
    /// stream is output when input is required or
    /// stream is input when output is required
    PmBadPtr = -9995,
    /// illegal midi data, e.g. missing EOX
    PmBadData = -9994,
    PmInternalError = -9993,
    /// buffer is already as large as it can be
    PmBufferMaxSize = -9992,
}
impl fmt::Display for PmError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { ffi::Pm_GetErrorText(*self) };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}
pub trait MaybeError<T> {
    fn try_from(err_code: T) -> Result<T, PmError>;
}
impl MaybeError<c_int> for PmError {
    fn try_from(err_code: c_int) -> Result<c_int, PmError> {
        match err_code {
            -10_000...-9992 | 0 | 1 => unsafe { Err(mem::transmute(err_code)) },
            _ => Ok(err_code),
        }
    }
}
<commit_msg>rustfmt<commit_after>use std::os::raw::{c_char, c_void, c_int};
use std::mem;
use std::default::Default;
use std::fmt;
use ffi;

pub type PmDeviceId = c_int;
pub type PortMidiStream = c_void;
pub type PmMessage = c_int;

pub type PmTimestamp = u32;
pub const PM_NO_DEVICE: PmDeviceId = -1;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct PmEvent {
    pub message: PmMessage,
    pub timestamp: PmTimestamp,
}
impl Default for PmEvent {
    fn default() -> Self {
        PmEvent {
            message: 0,
            timestamp: 0,
        }
    }
}

#[repr(C)]
pub struct PmDeviceInfo {
    /// this internal structure version
    pub struct_version: c_int,
    /// underlying MIDI API, e.g. MMSystem or DirectX
    pub interf: *const c_char,
    /// device name, e.g. USB MidiSport 1x1
    pub name: *const c_char,
    /// true iff input is available
    pub input: c_int,
    /// true iff output is available
    pub output: c_int,
    /// used by generic PortMidi code to do error checking on arguments
    pub opened: c_int,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum PmError {
    /// "no error" return that also indicates data available
    PmNoError = 0,
    /// "no error" return that also indicates data available
    PmGotData = 1,
    PmHostError = -10000,
    /// out of range or
    /// output device when input is requested or
    /// input device when output is requested or
    /// device is already opened
    PmInvalidDeviceId = -9999,
    PmInsufficientMemory = -9998,
    PmBufferTooSmall = -9997,
    PmBufferOverflow = -9996,
    /// PortMidiStream parameter is NULL or
    /// stream is not opened or
    /// stream is output when input is required or
    /// stream is input when output is required
    PmBadPtr = -9995,
    /// illegal midi data, e.g. missing EOX
    PmBadData = -9994,
    PmInternalError = -9993,
    /// buffer is already as large as it can be
    PmBufferMaxSize = -9992,
}
impl fmt::Display for PmError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str_ptr = unsafe { ffi::Pm_GetErrorText(*self) };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}
pub trait MaybeError<T> {
    fn try_from(err_code: T) -> Result<T, PmError>;
}
impl MaybeError<c_int> for PmError {
    fn try_from(err_code: c_int) -> Result<c_int, PmError> {
        match err_code {
            -10_000...-9992 | 0 | 1 => unsafe { Err(mem::transmute(err_code)) },
            _ => Ok(err_code),
        }
    }
}
<|endoftext|>


<commit_before>use lib::*;

use de::{Deserialize, Deserializer, Visitor, SeqVisitor, MapVisitor, Error};

/// A target for deserializers that want to ignore data. Implements Deserialize
/// and silently eats data given to it.
#[derive(Copy, Clone, Debug, Default)]
pub struct IgnoredAny;

impl<'de> Deserialize<'de> for IgnoredAny {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<IgnoredAny, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct IgnoredAnyVisitor;

        impl<'de> Visitor<'de> for IgnoredAnyVisitor {
            type Value = IgnoredAny;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("anything at all")
            }

            #[inline]
            fn visit_bool<E>(self, _: bool) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_i64<E>(self, _: i64) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_u64<E>(self, _: u64) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_f64<E>(self, _: f64) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_str<E>(self, _: &str) -> Result<IgnoredAny, E>
            where
                E: Error,
            {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_none<E>(self) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_some<D>(self, deserializer: D) -> Result<IgnoredAny, D::Error>
            where
                D: Deserializer<'de>,
            {
                IgnoredAny::deserialize(deserializer)
            }

            #[inline]
            fn visit_newtype_struct<D>(self, deserializer: D) -> Result<IgnoredAny, D::Error>
            where
                D: Deserializer<'de>,
            {
                IgnoredAny::deserialize(deserializer)
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<IgnoredAny, E> {
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_seq<V>(self, mut visitor: V) -> Result<IgnoredAny, V::Error>
            where
                V: SeqVisitor<'de>,
            {
                while let Some(_) = try!(visitor.visit::<IgnoredAny>()) {
                    // Gobble
                }
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_map<V>(self, mut visitor: V) -> Result<IgnoredAny, V::Error>
            where
                V: MapVisitor<'de>,
            {
                while let Some((_, _)) = try!(visitor.visit::<IgnoredAny, IgnoredAny>()) {
                    // Gobble
                }
                Ok(IgnoredAny)
            }

            #[inline]
            fn visit_bytes<E>(self, _: &[u8]) -> Result<IgnoredAny, E>
            where
                E: Error,
            {
                Ok(IgnoredAny)
            }
        }

        deserializer.deserialize_ignored_any(IgnoredAnyVisitor)
    }
}
<commit_msg>Allow using IgnoredAny as a visitor<commit_after>use lib::*;

use de::{Deserialize, Deserializer, Visitor, SeqVisitor, MapVisitor, Error};

/// A target for deserializers that want to ignore data. Implements Deserialize
/// and silently eats data given to it.
#[derive(Copy, Clone, Debug, Default)]
pub struct IgnoredAny;

impl<'de> Visitor<'de> for IgnoredAny {
    type Value = IgnoredAny;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("anything at all")
    }

    #[inline]
    fn visit_bool<E>(self, x: bool) -> Result<Self::Value, E> {
        let _ = x;
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_i64<E>(self, x: i64) -> Result<Self::Value, E> {
        let _ = x;
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
        let _ = x;
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
        let _ = x;
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
    where
        E: Error,
    {
        let _ = s;
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_none<E>(self) -> Result<Self::Value, E> {
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        IgnoredAny::deserialize(deserializer)
    }

    #[inline]
    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        IgnoredAny::deserialize(deserializer)
    }

    #[inline]
    fn visit_unit<E>(self) -> Result<Self::Value, E> {
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
    where
        V: SeqVisitor<'de>,
    {
        while let Some(IgnoredAny) = try!(visitor.visit()) {
            // Gobble
        }
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
    where
        V: MapVisitor<'de>,
    {
        while let Some((IgnoredAny, IgnoredAny)) = try!(visitor.visit()) {
            // Gobble
        }
        Ok(IgnoredAny)
    }

    #[inline]
    fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
    where
        E: Error,
    {
        let _ = bytes;
        Ok(IgnoredAny)
    }
}

impl<'de> Deserialize<'de> for IgnoredAny {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<IgnoredAny, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_ignored_any(IgnoredAny)
    }
}
<|endoftext|>


<commit_before>#![allow(warnings)]
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::abstract_const::{Node, NodeId};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;

pub fn is_const_evaluatable<'cx, 'tcx>(
    infcx: &InferCtxt<'cx, 'tcx>,
    def: ty::WithOptConstParam<DefId>,
    substs: SubstsRef<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    span: Span,
) -> Result<(), ErrorHandled> {
    debug!("is_const_evaluatable({:?}, {:?})", def, substs);
    if infcx.tcx.features().const_evaluatable_checked {
        if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) {
            for pred in param_env.caller_bounds() {
                match pred.skip_binders() {
                    ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
                        debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
                        if b_def == def && b_substs == substs {
                            debug!("is_const_evaluatable: caller_bound ~~> ok");
                            return Ok(());
                        } else if AbstractConst::new(infcx.tcx, b_def, b_substs)
                            .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct))
                        {
                            debug!("is_const_evaluatable: abstract_const ~~> ok");
                            return Ok(());
                        }
                    }
                    _ => {} // don't care
                }
            }
        }
    }

    let future_compat_lint = || {
        if let Some(local_def_id) = def.did.as_local() {
            infcx.tcx.struct_span_lint_hir(
                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
                infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
                span,
                |err| {
                    err.build("cannot use constants which depend on generic parameters in types")
                        .emit();
                },
            );
        }
    };

    // FIXME: We should only try to evaluate a given constant here if it is fully concrete
    // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
    //
    // We previously did not check this, so we only emit a future compat warning if
    // const evaluation succeeds and the given constant is still polymorphic for now
    // and hopefully soon change this to an error.
    //
    // See #74595 for more details about this.
    let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span));

    if concrete.is_ok() && substs.has_param_types_or_consts() {
        match infcx.tcx.def_kind(def.did) {
            DefKind::AnonConst => {
                let mir_body = if let Some(def) = def.as_const_arg() {
                    infcx.tcx.optimized_mir_of_const_arg(def)
                } else {
                    infcx.tcx.optimized_mir(def.did)
                };

                if mir_body.is_polymorphic {
                    future_compat_lint();
                }
            }
            _ => future_compat_lint(),
        }
    }

    debug!(?concrete, "is_const_evaluatable");
    concrete.map(drop)
}

/// A tree representing an anonymous constant.
///
/// This is only able to represent a subset of `MIR`,
/// and should not leak any information about desugarings.
#[derive(Clone, Copy)]
pub struct AbstractConst<'tcx> {
    pub inner: &'tcx [Node<'tcx>],
    pub substs: SubstsRef<'tcx>,
}

impl AbstractConst<'tcx> {
    pub fn new(
        tcx: TyCtxt<'tcx>,
        def: ty::WithOptConstParam<DefId>,
        substs: SubstsRef<'tcx>,
    ) -> Option<AbstractConst<'tcx>> {
        let inner = match (def.did.as_local(), def.const_param_did) {
            (Some(did), Some(param_did)) => {
                tcx.mir_abstract_const_of_const_arg((did, param_did))?
            }
            _ => tcx.mir_abstract_const(def.did)?,
        };

        Some(AbstractConst { inner, substs })
    }

    #[inline]
    pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
        AbstractConst { inner: &self.inner[..=node], substs: self.substs }
    }

    #[inline]
    pub fn root(self) -> Node<'tcx> {
        self.inner.last().copied().unwrap()
    }
}

struct AbstractConstBuilder<'a, 'tcx> {
    tcx: TyCtxt<'tcx>,
    body: &'a mir::Body<'tcx>,
    nodes: Vec<Node<'tcx>>,
    locals: IndexVec<mir::Local, NodeId>,
    checked_op_locals: BitSet<mir::Local>,
}

impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
    fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option<AbstractConstBuilder<'a, 'tcx>> {
        if body.is_cfg_cyclic() {
            return None;
        }

        Some(AbstractConstBuilder {
            tcx,
            body,
            nodes: vec![],
            locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
            checked_op_locals: BitSet::new_empty(body.local_decls.len()),
        })
    }

    fn add_node(&mut self, n: Node<'tcx>) -> NodeId {
        let len = self.nodes.len();
        self.nodes.push(n);
        len
    }

    fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option<NodeId> {
        debug!("operand_to_node: op={:?}", op);
        const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
        match op {
            mir::Operand::Copy(p) | mir::Operand::Move(p) => {
                if let Some(p) = p.as_local() {
                    debug_assert!(!self.checked_op_locals.contains(p));
                    Some(self.locals[p])
                } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
                    // Only allow field accesses on the result of checked operations.
                    if self.checked_op_locals.contains(p.local) {
                        Some(self.locals[p.local])
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            mir::Operand::Constant(ct) => Some(self.add_node(Node::Leaf(ct.literal))),
        }
    }

    fn check_binop(op: mir::BinOp) -> bool {
        use mir::BinOp::*;
        match op {
            Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le
            | Ne | Ge | Gt => true,
            Offset => false,
        }
    }

    fn build(mut self) -> Option<&'tcx [Node<'tcx>]> {
        let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
        loop {
            debug!("AbstractConstBuilder: block={:?}", block);
            for stmt in block.statements.iter() {
                debug!("AbstractConstBuilder: stmt={:?}", stmt);
                match stmt.kind {
                    StatementKind::Assign(box (ref place, ref rvalue)) => {
                        let local = place.as_local()?;
                        match *rvalue {
                            Rvalue::Use(ref operand) => {
                                self.locals[local] = self.operand_to_node(operand)?;
                            }
                            Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
                                let lhs = self.operand_to_node(lhs)?;
                                let rhs = self.operand_to_node(rhs)?;
                                self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
                                if op.is_checkable() {
                                    bug!("unexpected unchecked checkable binary operation");
                                }
                            }
                            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs)
                                if Self::check_binop(op) =>
                            {
                                let lhs = self.operand_to_node(lhs)?;
                                let rhs = self.operand_to_node(rhs)?;
                                self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
                                self.checked_op_locals.insert(local);
                            }
                            _ => return None,
                        }
                    }
                    _ => return None,
                }
            }

            debug!("AbstractConstBuilder: terminator={:?}", block.terminator());
            match block.terminator().kind {
                TerminatorKind::Goto { target } => {
                    block = &self.body.basic_blocks()[target];
                }
                TerminatorKind::Return => {
                    warn!(?self.nodes);
                    return { Some(self.tcx.arena.alloc_from_iter(self.nodes)) };
                }
                TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
                    let p = match cond {
                        mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
                        mir::Operand::Constant(_) => bug!("Unexpected assert"),
                    };

                    const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
                    debug!("proj: {:?}", p.projection);
                    if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
                        // Only allow asserts checking the result of a checked operation.
                        if self.checked_op_locals.contains(p.local) {
                            block = &self.body.basic_blocks()[target];
                            continue;
                        }
                    }

                    return None;
                }
                _ => return None,
            }
        }
    }
}

/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
pub(super) fn mir_abstract_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    def: ty::WithOptConstParam<LocalDefId>,
) -> Option<&'tcx [Node<'tcx>]> {
    if !tcx.features().const_evaluatable_checked {
        None
    } else {
        let body = tcx.mir_const(def).borrow();
        AbstractConstBuilder::new(tcx, &body)?.build()
    }
}

pub(super) fn try_unify_abstract_consts<'tcx>(
    tcx: TyCtxt<'tcx>,
    ((a, a_substs), (b, b_substs)): (
        (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
        (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
    ),
) -> bool {
    if let Some(a) = AbstractConst::new(tcx, a, a_substs) {
        if let Some(b) = AbstractConst::new(tcx, b, b_substs) {
            return try_unify(tcx, a, b);
        }
    }

    false
}

pub(super) fn try_unify<'tcx>(
    tcx: TyCtxt<'tcx>,
    a: AbstractConst<'tcx>,
    b: AbstractConst<'tcx>,
) -> bool {
    match (a.root(), b.root()) {
        (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
            let a_ct = a_ct.subst(tcx, a.substs);
            let b_ct = b_ct.subst(tcx, b.substs);
            match (a_ct.val, b_ct.val) {
                (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
                    a_param == b_param
                }
                (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
                // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
                // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                // means that we can't do anything with inference variables here.
                (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => false,
                // FIXME(const_evaluatable_checked): We may want to either actually try
                // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
                // this, for now we just return false here.
                _ => false,
            }
        }
        (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
            try_unify(tcx, a.subtree(al), b.subtree(bl))
                && try_unify(tcx, a.subtree(ar), b.subtree(br))
        }
        (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
            try_unify(tcx, a.subtree(av), b.subtree(bv))
        }
        (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
            if a_args.len() == b_args.len() =>
        {
            try_unify(tcx, a.subtree(a_f), b.subtree(b_f))
                && a_args
                    .iter()
                    .zip(b_args)
                    .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
        }
        _ => false,
    }
}
<commit_msg>refactor AbstractConstBuilder<commit_after>#![allow(warnings)]
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::abstract_const::{Node, NodeId};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;

pub fn is_const_evaluatable<'cx, 'tcx>(
    infcx: &InferCtxt<'cx, 'tcx>,
    def: ty::WithOptConstParam<DefId>,
    substs: SubstsRef<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    span: Span,
) -> Result<(), ErrorHandled> {
    debug!("is_const_evaluatable({:?}, {:?})", def, substs);
    if infcx.tcx.features().const_evaluatable_checked {
        if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs) {
            for pred in param_env.caller_bounds() {
                match pred.skip_binders() {
                    ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
                        debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
                        if b_def == def && b_substs == substs {
                            debug!("is_const_evaluatable: caller_bound ~~> ok");
                            return Ok(());
                        } else if AbstractConst::new(infcx.tcx, b_def, b_substs)
                            .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct))
                        {
                            debug!("is_const_evaluatable: abstract_const ~~> ok");
                            return Ok(());
                        }
                    }
                    _ => {} // don't care
                }
            }
        }
    }

    let future_compat_lint = || {
        if let Some(local_def_id) = def.did.as_local() {
            infcx.tcx.struct_span_lint_hir(
                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
                infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
                span,
                |err| {
                    err.build("cannot use constants which depend on generic parameters in types")
                        .emit();
                },
            );
        }
    };

    // FIXME: We should only try to evaluate a given constant here if it is fully concrete
    // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
    //
    // We previously did not check this, so we only emit a future compat warning if
    // const evaluation succeeds and the given constant is still polymorphic for now
    // and hopefully soon change this to an error.
    //
    // See #74595 for more details about this.
    let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span));

    if concrete.is_ok() && substs.has_param_types_or_consts() {
        match infcx.tcx.def_kind(def.did) {
            DefKind::AnonConst => {
                let mir_body = if let Some(def) = def.as_const_arg() {
                    infcx.tcx.optimized_mir_of_const_arg(def)
                } else {
                    infcx.tcx.optimized_mir(def.did)
                };

                if mir_body.is_polymorphic {
                    future_compat_lint();
                }
            }
            _ => future_compat_lint(),
        }
    }

    debug!(?concrete, "is_const_evaluatable");
    concrete.map(drop)
}

/// A tree representing an anonymous constant.
///
/// This is only able to represent a subset of `MIR`,
/// and should not leak any information about desugarings.
#[derive(Clone, Copy)]
pub struct AbstractConst<'tcx> {
    pub inner: &'tcx [Node<'tcx>],
    pub substs: SubstsRef<'tcx>,
}

impl AbstractConst<'tcx> {
    pub fn new(
        tcx: TyCtxt<'tcx>,
        def: ty::WithOptConstParam<DefId>,
        substs: SubstsRef<'tcx>,
    ) -> Option<AbstractConst<'tcx>> {
        let inner = match (def.did.as_local(), def.const_param_did) {
            (Some(did), Some(param_did)) => {
                tcx.mir_abstract_const_of_const_arg((did, param_did))?
            }
            _ => tcx.mir_abstract_const(def.did)?,
        };

        Some(AbstractConst { inner, substs })
    }

    #[inline]
    pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
        AbstractConst { inner: &self.inner[..=node], substs: self.substs }
    }

    #[inline]
    pub fn root(self) -> Node<'tcx> {
        self.inner.last().copied().unwrap()
    }
}

struct AbstractConstBuilder<'a, 'tcx> {
    tcx: TyCtxt<'tcx>,
    body: &'a mir::Body<'tcx>,
    nodes: Vec<Node<'tcx>>,
    locals: IndexVec<mir::Local, NodeId>,
    checked_op_locals: BitSet<mir::Local>,
}

impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
    fn new(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>) -> Option<AbstractConstBuilder<'a, 'tcx>> {
        if body.is_cfg_cyclic() {
            return None;
        }

        Some(AbstractConstBuilder {
            tcx,
            body,
            nodes: vec![],
            locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
            checked_op_locals: BitSet::new_empty(body.local_decls.len()),
        })
    }

    fn add_node(&mut self, n: Node<'tcx>) -> NodeId {
        let len = self.nodes.len();
        self.nodes.push(n);
        len
    }

    fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option<NodeId> {
        debug!("operand_to_node: op={:?}", op);
        const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
        match op {
            mir::Operand::Copy(p) | mir::Operand::Move(p) => {
                if let Some(p) = p.as_local() {
                    debug_assert!(!self.checked_op_locals.contains(p));
                    Some(self.locals[p])
                } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
                    // Only allow field accesses on the result of checked operations.
                    if self.checked_op_locals.contains(p.local) {
                        Some(self.locals[p.local])
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            mir::Operand::Constant(ct) => Some(self.add_node(Node::Leaf(ct.literal))),
        }
    }

    fn check_binop(op: mir::BinOp) -> bool {
        use mir::BinOp::*;
        match op {
            Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le
            | Ne | Ge | Gt => true,
            Offset => false,
        }
    }

    fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
        debug!("AbstractConstBuilder: stmt={:?}", stmt);
        match stmt.kind {
            StatementKind::Assign(box (ref place, ref rvalue)) => {
                let local = place.as_local()?;
                match *rvalue {
                    Rvalue::Use(ref operand) => {
                        self.locals[local] = self.operand_to_node(operand)?;
                    }
                    Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
                        let lhs = self.operand_to_node(lhs)?;
                        let rhs = self.operand_to_node(rhs)?;
                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
                        if op.is_checkable() {
                            bug!("unexpected unchecked checkable binary operation");
                        }
                    }
                    Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
                        let lhs = self.operand_to_node(lhs)?;
                        let rhs = self.operand_to_node(rhs)?;
                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
                        self.checked_op_locals.insert(local);
                    }
                    _ => return None,
                }
            }
            _ => return None,
        }

        Some(())
    }

    fn build_terminator(
        &mut self,
        terminator: &mir::Terminator<'tcx>,
    ) -> Option<Option<mir::BasicBlock>> {
        debug!("AbstractConstBuilder: terminator={:?}", terminator);
        match terminator.kind {
            TerminatorKind::Goto { target } => Some(Some(target)),
            TerminatorKind::Return => Some(None),
            TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
                let p = match cond {
                    mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
                    mir::Operand::Constant(_) => bug!("Unexpected assert"),
                };

                const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
                debug!("proj: {:?}", p.projection);
                if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
                    // Only allow asserts checking the result of a checked operation.
                    if self.checked_op_locals.contains(p.local) {
                        return Some(Some(target));
                    }
                }

                None
            }
            _ => None,
        }
    }

    fn build(mut self) -> Option<&'tcx [Node<'tcx>]> {
        let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
        loop {
            debug!("AbstractConstBuilder: block={:?}", block);
            for stmt in block.statements.iter() {
                self.build_statement(stmt)?;
            }

            if let Some(next) = self.build_terminator(block.terminator())? {
                block = &self.body.basic_blocks()[next];
            } else {
                return Some(self.tcx.arena.alloc_from_iter(self.nodes));
            }
        }
    }
}

/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
pub(super) fn mir_abstract_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    def: ty::WithOptConstParam<LocalDefId>,
) -> Option<&'tcx [Node<'tcx>]> {
    if tcx.features().const_evaluatable_checked {
        let body = tcx.mir_const(def).borrow();
        AbstractConstBuilder::new(tcx, &body)?.build()
    } else {
        None
    }
}

pub(super) fn try_unify_abstract_consts<'tcx>(
    tcx: TyCtxt<'tcx>,
    ((a, a_substs), (b, b_substs)): (
        (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
        (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
    ),
) -> bool {
    if let Some(a) = AbstractConst::new(tcx, a, a_substs) {
        if let Some(b) = AbstractConst::new(tcx, b, b_substs) {
            return try_unify(tcx, a, b);
        }
    }

    false
}

pub(super) fn try_unify<'tcx>(
    tcx: TyCtxt<'tcx>,
    a: AbstractConst<'tcx>,
    b: AbstractConst<'tcx>,
) -> bool {
    match (a.root(), b.root()) {
        (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
            let a_ct = a_ct.subst(tcx, a.substs);
            let b_ct = b_ct.subst(tcx, b.substs);
            match (a_ct.val, b_ct.val) {
                (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
                    a_param == b_param
                }
                (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
                // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
                // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                // means that we can't do anything with inference variables here.
                (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => false,
                // FIXME(const_evaluatable_checked): We may want to either actually try
                // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
                // this, for now we just return false here.
                _ => false,
            }
        }
        (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
            try_unify(tcx, a.subtree(al), b.subtree(bl))
                && try_unify(tcx, a.subtree(ar), b.subtree(br))
        }
        (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
            try_unify(tcx, a.subtree(av), b.subtree(bv))
        }
        (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
            if a_args.len() == b_args.len() =>
        {
            try_unify(tcx, a.subtree(a_f), b.subtree(b_f))
                && a_args
                    .iter()
                    .zip(b_args)
                    .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
        }
        _ => false,
    }
}
<|endoftext|>


<commit_before>//! Tidy check to ensure that crate `edition` is '2018'

use std::path::Path;

fn filter_dirs(path: &Path) -> bool {
    // FIXME: just use super::filter_dirs after the submodules are updated.
    if super::filter_dirs(path) {
        return true;
    }
    let skip = [
        "src/doc/book/second-edition",
        "src/doc/book/2018-edition",
        "src/doc/book/ci/stable-check",
        "src/doc/reference/stable-check",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn is_edition_2018(mut line: &str) -> bool {
    line = line.trim();
    line == "edition = \"2018\"" || line == "edition = \'2018\'"
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(
        path,
        &mut |path| filter_dirs(path) || path.ends_with("src/test"),
        &mut |entry, contents| {
            let file = entry.path();
            let filename = file.file_name().unwrap();
            if filename != "Cargo.toml" {
                return;
            }
            let has_edition = contents.lines().any(is_edition_2018);
            if !has_edition {
                tidy_error!(
                    bad,
                    "{} doesn't have `edition = \"2018\"` on a separate line",
                    file.display()
                );
            }
        },
    );
}
<commit_msg>tidy: Remove edition filter exceptions.<commit_after>//! Tidy check to ensure that crate `edition` is '2018'

use std::path::Path;

fn is_edition_2018(mut line: &str) -> bool {
    line = line.trim();
    line == "edition = \"2018\"" || line == "edition = \'2018\'"
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(
        path,
        &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
        &mut |entry, contents| {
            let file = entry.path();
            let filename = file.file_name().unwrap();
            if filename != "Cargo.toml" {
                return;
            }
            let has_edition = contents.lines().any(is_edition_2018);
            if !has_edition {
                tidy_error!(
                    bad,
                    "{} doesn't have `edition = \"2018\"` on a separate line",
                    file.display()
                );
            }
        },
    );
}
<|endoftext|>