<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_config::config::HANDSHAKE_VERSION;
use aptos_crypto::{bls12381, ed25519::Ed25519PublicKey, x25519};
use aptos_types::{
    account_address::AccountAddress,
    chain_id::ChainId,
    network_address::{DnsName, NetworkAddress, Protocol},
    transaction::authenticator::AuthenticationKey,
};
use serde::{Deserialize, Serialize};
use std::{
    convert::TryFrom,
    fs::File,
    io::Read,
    net::{Ipv4Addr, Ipv6Addr, ToSocketAddrs},
    path::Path,
    str::FromStr,
};
use vm_genesis::{Validator, ValidatorWithCommissionRate};

/// Template for setting up Github for Genesis
///
#[derive(Debug, Deserialize, Serialize)]
pub struct Layout {
    /// Root key for the blockchain
    /// TODO: In the future, we won't need a root key
    pub root_key: Option<Ed25519PublicKey>,
    /// List of usernames or identifiers
    pub users: Vec<String>,
    /// ChainId for the target network
    pub chain_id: ChainId,
    /// Whether to allow new validators to join the set after genesis
    #[serde(default)]
    pub allow_new_validators: bool,
    /// Duration of an epoch
    pub epoch_duration_secs: u64,
    pub is_test: bool,
    /// Minimum stake to be in the validator set
    pub min_stake: u64,
    /// Minimum number of votes to consider a proposal valid.
    pub min_voting_threshold: u128,
    /// Maximum stake to be in the validator set
    pub max_stake: u64,
    /// Minimum number of seconds to lockup staked coins
    pub recurring_lockup_duration_secs: u64,
    /// Required amount of stake to create proposals.
    pub required_proposer_stake: u64,
    /// Percentage of stake given out as rewards a year (0-100%).
    pub rewards_apy_percentage: u64,
    /// Voting duration for a proposal in seconds.
    pub voting_duration_secs: u64,
    /// % of current epoch's total voting power that can be added in this epoch.
    pub voting_power_increase_limit: u64,
}

impl Layout {
    /// Read the layout from a YAML file on disk
    pub fn from_disk(path: &Path) -> anyhow::Result<Self> {
        let mut file = File::open(&path).map_err(|e| {
            anyhow::Error::msg(format!("Failed to open file {}, {}", path.display(), e))
        })?;
        let mut contents = String::new();
        file.read_to_string(&mut contents).map_err(|e| {
            anyhow::Error::msg(format!("Failed to read file {}, {}", path.display(), e))
        })?;

        Ok(serde_yaml::from_str(&contents)?)
    }
}

impl Default for Layout {
    fn default() -> Self {
        Layout {
            root_key: None,
            users: vec![],
            chain_id: ChainId::test(),
            allow_new_validators: false,
            epoch_duration_secs: 7_200,
            is_test: true,
            min_stake: 100_000_000_000_000,
            min_voting_threshold: 100_000_000_000_000,
            max_stake: 100_000_000_000_000_000,
            recurring_lockup_duration_secs: 86_400,
            required_proposer_stake: 100_000_000_000_000,
            rewards_apy_percentage: 10,
            voting_duration_secs: 43_200,
            voting_power_increase_limit: 20,
        }
    }
}

/// A set of configuration needed to add a Validator to genesis
///
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ValidatorConfiguration {
    /// Account address
    pub owner_account_address: AccountAddress,
    /// Key used for signing transactions with the account
    pub owner_account_public_key: Ed25519PublicKey,
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub voter_account_address: AccountAddress,
    pub voter_account_public_key: Ed25519PublicKey,
    /// Key used for signing in consensus
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consensus_public_key: Option<bls12381::PublicKey>,
    /// Corresponding proof of possession of consensus public key
    #[serde(skip_serializing_if = "Option::is_none")]
    pub proof_of_possession: Option<bls12381::ProofOfPossession>,
    /// Public key used for validator network identity (same as account address)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validator_network_public_key: Option<x25519::PublicKey>,
    /// Host for validator which can be an IP or a DNS name
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validator_host: Option<HostAndPort>,
    /// Public key used for full node network identity (same as account address)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub full_node_network_public_key: Option<x25519::PublicKey>,
    /// Host for full node which can be an IP or a DNS name and is optional
    #[serde(skip_serializing_if = "Option::is_none")]
    pub full_node_host: Option<HostAndPort>,
    /// Stake amount for consensus
    pub stake_amount: u64,
    /// Commission percentage for validator
    pub commission_percentage: u64,
    /// Whether the validator should be joining the validator set during genesis.
    /// If set to false, the validator will be fully initialized but won't be added to the
    /// validator set.
    pub join_during_genesis: bool,
}

impl TryFrom<ValidatorConfiguration> for ValidatorWithCommissionRate {
    type Error = anyhow::Error;

    fn try_from(config: ValidatorConfiguration) -> Result<Self, Self::Error> {
        let validator_commission_percentage = config.commission_percentage;
        let join_during_genesis = config.join_during_genesis;
        Ok(ValidatorWithCommissionRate {
            validator: config.try_into()?,
            validator_commission_percentage,
            join_during_genesis,
        })
    }
}

impl TryFrom<ValidatorConfiguration> for Validator {
    type Error = anyhow::Error;

    fn try_from(config: ValidatorConfiguration) -> Result<Self, Self::Error> {
        let validator_addresses = if let Some(validator_host) = config.validator_host {
            if let Some(validator_network_public_key) = config.validator_network_public_key {
                vec![validator_host
                    .as_network_address(validator_network_public_key)
                    .unwrap()]
            } else {
                return Err(anyhow::Error::msg(
                    "Validator addresses specified, but not validator network key",
                ));
            }
        } else {
            vec![]
        };

        let full_node_addresses = if let Some(full_node_host) = config.full_node_host {
            if let Some(full_node_network_key) = config.full_node_network_public_key {
                vec![full_node_host
                    .as_network_address(full_node_network_key)
                    .unwrap()]
            } else {
                return Err(anyhow::Error::msg(
                    "Full node host specified, but not full node network key",
                ));
            }
        } else {
            vec![]
        };

        let auth_key = AuthenticationKey::ed25519(&config.owner_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.owner_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "owner_account_address {} does not match account key derived one {}",
                config.owner_account_address, derived_address
            )));
        }

        let auth_key = AuthenticationKey::ed25519(&config.operator_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.operator_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "operator_account_address {} does not match account key derived one {}",
                config.operator_account_address, derived_address
            )));
        }

        let auth_key = AuthenticationKey::ed25519(&config.voter_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.voter_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "voter_account_address {} does not match account key derived one {}",
                config.voter_account_address, derived_address
            )));
        }

        let consensus_pubkey = if let Some(consensus_public_key) = config.consensus_public_key {
            consensus_public_key.to_bytes().to_vec()
        } else {
            vec![]
        };
        let proof_of_possession = if let Some(pop) = config.proof_of_possession {
            pop.to_bytes().to_vec()
        } else {
            vec![]
        };

        Ok(Validator {
            owner_address: config.owner_account_address,
            operator_address: config.operator_account_address,
            voter_address: config.voter_account_address,
            consensus_pubkey,
            proof_of_possession,
            network_addresses: bcs::to_bytes(&validator_addresses).unwrap(),
            full_node_network_addresses: bcs::to_bytes(&full_node_addresses).unwrap(),
            stake_amount: config.stake_amount,
        })
    }
}

const LOCALHOST: &str = "localhost";

/// Combined Host (DnsName or IP) and port
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HostAndPort {
    pub host: DnsName,
    pub port: u16,
}

impl HostAndPort {
    pub fn local(port: u16) -> anyhow::Result<HostAndPort> {
        Ok(HostAndPort {
            host: DnsName::try_from(LOCALHOST.to_string())?,
            port,
        })
    }

    pub fn as_network_address(&self, key: x25519::PublicKey) -> anyhow::Result<NetworkAddress> {
        let host = self.host.to_string();

        // Since DnsName supports IPs as well, let's properly fix what the type is
        let host_protocol = if let Ok(ip) = Ipv4Addr::from_str(&host) {
            Protocol::Ip4(ip)
        } else if let Ok(ip) = Ipv6Addr::from_str(&host) {
            Protocol::Ip6(ip)
        } else {
            Protocol::Dns(self.host.clone())
        };
        let port_protocol = Protocol::Tcp(self.port);
        let noise_protocol = Protocol::NoiseIK(key);
        let handshake_protocol = Protocol::Handshake(HANDSHAKE_VERSION);

        Ok(NetworkAddress::try_from(vec![
            host_protocol,
            port_protocol,
            noise_protocol,
            handshake_protocol,
        ])?)
    }
}

impl TryFrom<&NetworkAddress> for HostAndPort {
    type Error = anyhow::Error;

    fn try_from(address: &NetworkAddress) -> Result<Self, Self::Error> {
        let socket_addr = address.to_socket_addrs()?.next().unwrap();
        HostAndPort::from_str(&socket_addr.to_string())
    }
}

impl FromStr for HostAndPort {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split(':').collect();
        if parts.len() != 2 {
            Err(anyhow::Error::msg(
                "Invalid host and port, must be of the form 'host:port` e.g. '127.0.0.1:6180'",
            ))
        } else {
            let host = DnsName::from_str(*parts.first().unwrap())?;
            let port = u16::from_str(parts.get(1).unwrap())?;
            Ok(HostAndPort { host, port })
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OwnerConfiguration {
    pub owner_account_address: AccountAddress,
    pub owner_account_public_key: Ed25519PublicKey,
    pub voter_account_address: AccountAddress,
    pub voter_account_public_key: Ed25519PublicKey,
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub stake_amount: u64,
    pub commission_percentage: u64,
    pub join_during_genesis: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OperatorConfiguration {
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub consensus_public_key: bls12381::PublicKey,
    pub consensus_proof_of_possession: bls12381::ProofOfPossession,
    pub validator_network_public_key: x25519::PublicKey,
    pub validator_host: HostAndPort,
    pub full_node_network_public_key: Option<x25519::PublicKey>,
    pub full_node_host: Option<HostAndPort>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StringOwnerConfiguration {
    pub owner_account_address: Option<String>,
    pub owner_account_public_key: Option<String>,
    pub voter_account_address: Option<String>,
    pub voter_account_public_key: Option<String>,
    pub operator_account_address: Option<String>,
    pub operator_account_public_key: Option<String>,
    pub stake_amount: Option<String>,
    pub commission_percentage: Option<String>,
    pub join_during_genesis: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StringOperatorConfiguration {
    pub operator_account_address: Option<String>,
    pub operator_account_public_key: Option<String>,
    pub consensus_public_key: Option<String>,
    pub consensus_proof_of_possession: Option<String>,
    pub validator_network_public_key: Option<String>,
    pub validator_host: HostAndPort,
    pub full_node_network_public_key: Option<String>,
    pub full_node_host: Option<HostAndPort>,
}
<commit_msg>[genesis] Make is test optional as a layout field<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_config::config::HANDSHAKE_VERSION;
use aptos_crypto::{bls12381, ed25519::Ed25519PublicKey, x25519};
use aptos_types::{
    account_address::AccountAddress,
    chain_id::ChainId,
    network_address::{DnsName, NetworkAddress, Protocol},
    transaction::authenticator::AuthenticationKey,
};
use serde::{Deserialize, Serialize};
use std::{
    convert::TryFrom,
    fs::File,
    io::Read,
    net::{Ipv4Addr, Ipv6Addr, ToSocketAddrs},
    path::Path,
    str::FromStr,
};
use vm_genesis::{Validator, ValidatorWithCommissionRate};

/// Template for setting up Github for Genesis
///
#[derive(Debug, Deserialize, Serialize)]
pub struct Layout {
    /// Root key for the blockchain
    /// TODO: In the future, we won't need a root key
    pub root_key: Option<Ed25519PublicKey>,
    /// List of usernames or identifiers
    pub users: Vec<String>,
    /// ChainId for the target network
    pub chain_id: ChainId,
    /// Whether to allow new validators to join the set after genesis
    ///
    /// Ignored for mainnet
    #[serde(default)]
    pub allow_new_validators: bool,
    /// Duration of an epoch
    pub epoch_duration_secs: u64,
    /// Whether this is a test network or not
    ///
    /// Ignored for mainnet
    #[serde(default)]
    pub is_test: bool,
    /// Minimum stake to be in the validator set
    pub min_stake: u64,
    /// Minimum number of votes to consider a proposal valid.
    pub min_voting_threshold: u128,
    /// Maximum stake to be in the validator set
    pub max_stake: u64,
    /// Minimum number of seconds to lockup staked coins
    pub recurring_lockup_duration_secs: u64,
    /// Required amount of stake to create proposals.
    pub required_proposer_stake: u64,
    /// Percentage of stake given out as rewards a year (0-100%).
    pub rewards_apy_percentage: u64,
    /// Voting duration for a proposal in seconds.
    pub voting_duration_secs: u64,
    /// % of current epoch's total voting power that can be added in this epoch.
    pub voting_power_increase_limit: u64,
}

impl Layout {
    /// Read the layout from a YAML file on disk
    pub fn from_disk(path: &Path) -> anyhow::Result<Self> {
        let mut file = File::open(&path).map_err(|e| {
            anyhow::Error::msg(format!("Failed to open file {}, {}", path.display(), e))
        })?;
        let mut contents = String::new();
        file.read_to_string(&mut contents).map_err(|e| {
            anyhow::Error::msg(format!("Failed to read file {}, {}", path.display(), e))
        })?;

        Ok(serde_yaml::from_str(&contents)?)
    }
}

impl Default for Layout {
    fn default() -> Self {
        Layout {
            root_key: None,
            users: vec![],
            chain_id: ChainId::test(),
            allow_new_validators: false,
            epoch_duration_secs: 7_200,
            is_test: true,
            min_stake: 100_000_000_000_000,
            min_voting_threshold: 100_000_000_000_000,
            max_stake: 100_000_000_000_000_000,
            recurring_lockup_duration_secs: 86_400,
            required_proposer_stake: 100_000_000_000_000,
            rewards_apy_percentage: 10,
            voting_duration_secs: 43_200,
            voting_power_increase_limit: 20,
        }
    }
}

/// A set of configuration needed to add a Validator to genesis
///
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ValidatorConfiguration {
    /// Account address
    pub owner_account_address: AccountAddress,
    /// Key used for signing transactions with the account
    pub owner_account_public_key: Ed25519PublicKey,
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub voter_account_address: AccountAddress,
    pub voter_account_public_key: Ed25519PublicKey,
    /// Key used for signing in consensus
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consensus_public_key: Option<bls12381::PublicKey>,
    /// Corresponding proof of possession of consensus public key
    #[serde(skip_serializing_if = "Option::is_none")]
    pub proof_of_possession: Option<bls12381::ProofOfPossession>,
    /// Public key used for validator network identity (same as account address)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validator_network_public_key: Option<x25519::PublicKey>,
    /// Host for validator which can be an IP or a DNS name
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validator_host: Option<HostAndPort>,
    /// Public key used for full node network identity (same as account address)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub full_node_network_public_key: Option<x25519::PublicKey>,
    /// Host for full node which can be an IP or a DNS name and is optional
    #[serde(skip_serializing_if = "Option::is_none")]
    pub full_node_host: Option<HostAndPort>,
    /// Stake amount for consensus
    pub stake_amount: u64,
    /// Commission percentage for validator
    pub commission_percentage: u64,
    /// Whether the validator should be joining the validator set during genesis.
    /// If set to false, the validator will be fully initialized but won't be added to the
    /// validator set.
    pub join_during_genesis: bool,
}

impl TryFrom<ValidatorConfiguration> for ValidatorWithCommissionRate {
    type Error = anyhow::Error;

    fn try_from(config: ValidatorConfiguration) -> Result<Self, Self::Error> {
        let validator_commission_percentage = config.commission_percentage;
        let join_during_genesis = config.join_during_genesis;
        Ok(ValidatorWithCommissionRate {
            validator: config.try_into()?,
            validator_commission_percentage,
            join_during_genesis,
        })
    }
}

impl TryFrom<ValidatorConfiguration> for Validator {
    type Error = anyhow::Error;

    fn try_from(config: ValidatorConfiguration) -> Result<Self, Self::Error> {
        let validator_addresses = if let Some(validator_host) = config.validator_host {
            if let Some(validator_network_public_key) = config.validator_network_public_key {
                vec![validator_host
                    .as_network_address(validator_network_public_key)
                    .unwrap()]
            } else {
                return Err(anyhow::Error::msg(
                    "Validator addresses specified, but not validator network key",
                ));
            }
        } else {
            vec![]
        };

        let full_node_addresses = if let Some(full_node_host) = config.full_node_host {
            if let Some(full_node_network_key) = config.full_node_network_public_key {
                vec![full_node_host
                    .as_network_address(full_node_network_key)
                    .unwrap()]
            } else {
                return Err(anyhow::Error::msg(
                    "Full node host specified, but not full node network key",
                ));
            }
        } else {
            vec![]
        };

        let auth_key = AuthenticationKey::ed25519(&config.owner_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.owner_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "owner_account_address {} does not match account key derived one {}",
                config.owner_account_address, derived_address
            )));
        }

        let auth_key = AuthenticationKey::ed25519(&config.operator_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.operator_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "operator_account_address {} does not match account key derived one {}",
                config.operator_account_address, derived_address
            )));
        }

        let auth_key = AuthenticationKey::ed25519(&config.voter_account_public_key);
        let derived_address = auth_key.derived_address();
        if config.voter_account_address != derived_address {
            return Err(anyhow::Error::msg(format!(
                "voter_account_address {} does not match account key derived one {}",
                config.voter_account_address, derived_address
            )));
        }

        let consensus_pubkey = if let Some(consensus_public_key) = config.consensus_public_key {
            consensus_public_key.to_bytes().to_vec()
        } else {
            vec![]
        };
        let proof_of_possession = if let Some(pop) = config.proof_of_possession {
            pop.to_bytes().to_vec()
        } else {
            vec![]
        };

        Ok(Validator {
            owner_address: config.owner_account_address,
            operator_address: config.operator_account_address,
            voter_address: config.voter_account_address,
            consensus_pubkey,
            proof_of_possession,
            network_addresses: bcs::to_bytes(&validator_addresses).unwrap(),
            full_node_network_addresses: bcs::to_bytes(&full_node_addresses).unwrap(),
            stake_amount: config.stake_amount,
        })
    }
}

const LOCALHOST: &str = "localhost";

/// Combined Host (DnsName or IP) and port
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HostAndPort {
    pub host: DnsName,
    pub port: u16,
}

impl HostAndPort {
    pub fn local(port: u16) -> anyhow::Result<HostAndPort> {
        Ok(HostAndPort {
            host: DnsName::try_from(LOCALHOST.to_string())?,
            port,
        })
    }

    pub fn as_network_address(&self, key: x25519::PublicKey) -> anyhow::Result<NetworkAddress> {
        let host = self.host.to_string();

        // Since DnsName supports IPs as well, let's properly fix what the type is
        let host_protocol = if let Ok(ip) = Ipv4Addr::from_str(&host) {
            Protocol::Ip4(ip)
        } else if let Ok(ip) = Ipv6Addr::from_str(&host) {
            Protocol::Ip6(ip)
        } else {
            Protocol::Dns(self.host.clone())
        };
        let port_protocol = Protocol::Tcp(self.port);
        let noise_protocol = Protocol::NoiseIK(key);
        let handshake_protocol = Protocol::Handshake(HANDSHAKE_VERSION);

        Ok(NetworkAddress::try_from(vec![
            host_protocol,
            port_protocol,
            noise_protocol,
            handshake_protocol,
        ])?)
    }
}

impl TryFrom<&NetworkAddress> for HostAndPort {
    type Error = anyhow::Error;

    fn try_from(address: &NetworkAddress) -> Result<Self, Self::Error> {
        let socket_addr = address.to_socket_addrs()?.next().unwrap();
        HostAndPort::from_str(&socket_addr.to_string())
    }
}

impl FromStr for HostAndPort {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split(':').collect();
        if parts.len() != 2 {
            Err(anyhow::Error::msg(
                "Invalid host and port, must be of the form 'host:port` e.g. '127.0.0.1:6180'",
            ))
        } else {
            let host = DnsName::from_str(*parts.first().unwrap())?;
            let port = u16::from_str(parts.get(1).unwrap())?;
            Ok(HostAndPort { host, port })
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OwnerConfiguration {
    pub owner_account_address: AccountAddress,
    pub owner_account_public_key: Ed25519PublicKey,
    pub voter_account_address: AccountAddress,
    pub voter_account_public_key: Ed25519PublicKey,
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub stake_amount: u64,
    pub commission_percentage: u64,
    pub join_during_genesis: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OperatorConfiguration {
    pub operator_account_address: AccountAddress,
    pub operator_account_public_key: Ed25519PublicKey,
    pub consensus_public_key: bls12381::PublicKey,
    pub consensus_proof_of_possession: bls12381::ProofOfPossession,
    pub validator_network_public_key: x25519::PublicKey,
    pub validator_host: HostAndPort,
    pub full_node_network_public_key: Option<x25519::PublicKey>,
    pub full_node_host: Option<HostAndPort>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StringOwnerConfiguration {
    pub owner_account_address: Option<String>,
    pub owner_account_public_key: Option<String>,
    pub voter_account_address: Option<String>,
    pub voter_account_public_key: Option<String>,
    pub operator_account_address: Option<String>,
    pub operator_account_public_key: Option<String>,
    pub stake_amount: Option<String>,
    pub commission_percentage: Option<String>,
    pub join_during_genesis: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StringOperatorConfiguration {
    pub operator_account_address: Option<String>,
    pub operator_account_public_key: Option<String>,
    pub consensus_public_key: Option<String>,
    pub consensus_proof_of_possession: Option<String>,
    pub validator_network_public_key: Option<String>,
    pub validator_host: HostAndPort,
    pub full_node_network_public_key: Option<String>,
    pub full_node_host: Option<HostAndPort>,
}
<|endoftext|>


<commit_before>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        self.files.watcher = match get::<&str>(value, "/files/watcher") {
            Some("client") => FilesWatcher::Client,
            Some("notify") | _ => FilesWatcher::Notify
        };
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        if let Some(mut args) = get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            if !args.is_empty() {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
        } else if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
            set(value, "/rustfmt/extraArgs", extra_args);
        }

        if let Some(false) = get(value, "/checkOnSave/enable") {
            self.check = None;
        } else {
            if let Some(mut args) = get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                if !args.is_empty() {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    });
                }

            } else if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
            {
                set(value, "/checkOnSave/extraArgs", extra_args);
                set(value, "/checkOnSave/command", command);
                set(value, "/checkOnSave/allTargets", all_targets);
            }
        };

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<commit_msg>Remove explicit generic type parameter<commit_after>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use lsp_types::TextDocumentClientCapabilities;
use ra_flycheck::FlycheckConfig;
use ra_ide::{CompletionConfig, InlayHintsConfig};
use ra_project_model::CargoConfig;
use serde::Deserialize;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub with_sysroot: bool,
    pub publish_diagnostics: bool,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<String>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub check: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub call_info_full: bool,
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub workspace_loaded: bool,
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt {
        extra_args: Vec<String>,
    },
    #[allow(unused)]
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig {
                workspace_loaded: true,
                cargo_toml_not_found: true,
            },

            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            check: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                extra_args: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
            },
            call_info_full: true,
        }
    }
}

impl Config {
    #[rustfmt::skip]
    pub fn update(&mut self, value: &serde_json::Value) {
        log::info!("Config::update({:#})", value);

        let client_caps = self.client_caps.clone();
        *self = Default::default();
        self.client_caps = client_caps;

        set(value, "/withSysroot", &mut self.with_sysroot);
        set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
        set(value, "/lruCapacity", &mut self.lru_capacity);
        self.files.watcher = match get(value, "/files/watcher") {
            Some("client") => FilesWatcher::Client,
            Some("notify") | _ => FilesWatcher::Notify
        };
        set(value, "/notifications/workspaceLoaded", &mut self.notifications.workspace_loaded);
        set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);

        set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
        set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
        set(value, "/cargo/features", &mut self.cargo.features);
        set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
        if let Some(mut args) = get::<Vec<String>>(value, "/rustfmt/overrideCommand") {
            if !args.is_empty() {
                let command = args.remove(0);
                self.rustfmt = RustfmtConfig::CustomCommand {
                    command,
                    args,
                }
            }
        } else if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
            set(value, "/rustfmt/extraArgs", extra_args);
        }

        if let Some(false) = get(value, "/checkOnSave/enable") {
            self.check = None;
        } else {
            if let Some(mut args) = get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
                if !args.is_empty() {
                    let command = args.remove(0);
                    self.check = Some(FlycheckConfig::CustomCommand {
                        command,
                        args,
                    });
                }

            } else if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
            {
                set(value, "/checkOnSave/extraArgs", extra_args);
                set(value, "/checkOnSave/command", command);
                set(value, "/checkOnSave/allTargets", all_targets);
            }
        };

        set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
        set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
        set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
        set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
        set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
        set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
        set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
        set(value, "/callInfo/full", &mut self.call_info_full);

        log::info!("Config::update() = {:#?}", self);

        fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
            value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
        }

        fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
            if let Some(new_value) = get(value, pointer) {
                *slot = new_value
            }
        }
    }

    pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
        if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
            self.client_caps.location_link = value;
        }
        if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
            self.client_caps.line_folding_only = value
        }
    }
}
<|endoftext|>


<commit_before>pub enum Operator {
    And,
    Or
}

impl Operator {
    pub fn to_sql(&self) -> &str {
        match *self {
            Operator::And => "AND",
            Operator::Or => "OR"
        }
    }
}

trait ToSQL {
    fn to_sql(&self) -> String;
}

struct Where<'a, T: 'a> {
    pub operator: Operator,
    pub clause: &'a [T]
}

impl<'a> ToSQL for &'a str {
    fn to_sql(&self) -> String {
        self.to_string()
    }
}

impl<'a, T: ToSQL> ToSQL for Where<'a, T> {
    fn to_sql(&self) -> String {
        let operator = &format!(" {} ", self.operator.to_sql());
        let mut rv = String::new();
        rv.push('(');
        rv.push_str(&self.clause.into_iter()
                    .map(|x| x.to_sql())
                    .collect::<Vec<_>>()
                    .join(operator));
        rv.push(')');
        rv
    }
}

impl<'a, T: ToSQL> ToSQL for &'a Where<'a, T>{
    fn to_sql(&self) -> String {
        (**self).to_sql()
    }
}

#[cfg(test)]
mod tests {
    use super::{Operator, ToSQL, Where};

    #[test]
    fn test_operator() {
        let and = Operator::And;
        let or = Operator::Or;

        assert_eq!(and.to_sql(), "AND");
        assert_eq!(or.to_sql(), "OR");
    }

    #[test]
    fn test_alone_where() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo=bar", "fizz=bazz"]
        };
        assert_eq!(foo.to_sql(), "(foo=bar AND fizz=bazz".to_string())
    }

    #[test]
    fn test_nested_where_clauses() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo == bar", "fizz == bazz"]
        };

        let bar = Where {
            operator: Operator::And,
            clause: &["a == b", "c == d"]
        };

        let bazz = Where {
            operator: Operator::Or,
            clause: &[&foo, &bar]
        };

        assert_eq!(bazz.to_sql(), "(foo == bar AND fizz == bazz) OR (a == b AND c == d)".to_string());
    }

    #[test]
    fn test_really_nested_where_clauses() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo == bar", "fizz == bazz"]
        };

        let bar = Where {
            operator: Operator::And,
            clause: &["a == b", "c == d"]
        };

        let bazz1 = Where {
            operator: Operator::Or,
            clause: &[&foo, &bar]
        };

        let bazz2 = Where {
            operator: Operator::Or,
            clause: &[&bar, &foo]
        };

        let fizz = Where {
            operator: Operator::And,
            clause: &[&bazz1, &bazz2]
        };

        assert_eq!(fizz.to_sql(), "(((foo == bar AND fizz == bazz) OR (a == b AND c == d)) AND ((a == b AND c == d) OR (foo == bar AND fizz == bazz)))".to_string());
    }
}
<commit_msg>Fixed where_clause tests<commit_after>pub enum Operator {
    And,
    Or
}

impl Operator {
    pub fn to_sql(&self) -> &str {
        match *self {
            Operator::And => "AND",
            Operator::Or => "OR"
        }
    }
}

trait ToSQL {
    fn to_sql(&self) -> String;
}

struct Where<'a, T: 'a> {
    pub operator: Operator,
    pub clause: &'a [T]
}

impl<'a> ToSQL for &'a str {
    fn to_sql(&self) -> String {
        self.to_string()
    }
}

impl<'a, T: ToSQL> ToSQL for Where<'a, T> {
    fn to_sql(&self) -> String {
        let operator = &format!(" {} ", self.operator.to_sql());
        let mut rv = String::new();
        rv.push('(');
        rv.push_str(&self.clause.into_iter()
                    .map(|x| x.to_sql())
                    .collect::<Vec<_>>()
                    .join(operator));
        rv.push(')');
        rv
    }
}

impl<'a, T: ToSQL> ToSQL for &'a Where<'a, T>{
    fn to_sql(&self) -> String {
        (**self).to_sql()
    }
}

#[cfg(test)]
mod tests {
    use super::{Operator, ToSQL, Where};

    #[test]
    fn test_operator() {
        let and = Operator::And;
        let or = Operator::Or;

        assert_eq!(and.to_sql(), "AND");
        assert_eq!(or.to_sql(), "OR");
    }

    #[test]
    fn test_alone_where() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo=bar", "fizz=bazz"]
        };
        assert_eq!(foo.to_sql(), "(foo=bar AND fizz=bazz)".to_string())
    }

    #[test]
    fn test_nested_where_clauses() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo == bar", "fizz == bazz"]
        };

        let bar = Where {
            operator: Operator::And,
            clause: &["a == b", "c == d"]
        };

        let bazz = Where {
            operator: Operator::Or,
            clause: &[&foo, &bar]
        };

        assert_eq!(bazz.to_sql(), "((foo == bar AND fizz == bazz) OR (a == b AND c == d))".to_string());
    }

    #[test]
    fn test_really_nested_where_clauses() {
        let foo = Where {
            operator: Operator::And,
            clause: &["foo == bar", "fizz == bazz"]
        };

        let bar = Where {
            operator: Operator::And,
            clause: &["a == b", "c == d"]
        };

        let bazz1 = Where {
            operator: Operator::Or,
            clause: &[&foo, &bar]
        };

        let bazz2 = Where {
            operator: Operator::Or,
            clause: &[&bar, &foo]
        };

        let fizz = Where {
            operator: Operator::And,
            clause: &[&bazz1, &bazz2]
        };

        assert_eq!(fizz.to_sql(), "(((foo == bar AND fizz == bazz) OR (a == b AND c == d)) AND ((a == b AND c == d) OR (foo == bar AND fizz == bazz)))".to_string());
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp;
use std::io::{self, BufRead, Read, Write};
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Duration;

use futures::{Future, Stream};
use kcp::{Error as KcpError, get_conv};
use mio::{self, Evented, PollOpt, Ready, Registration, SetReadiness, Token};
use tokio_core::reactor::Handle;

use session::{KcpClientSession, KcpServerSession, KcpSession, KcpSessionMode, KcpSessionUpdater};
use skcp::SharedKcp;

/// Base Io object for KCP
struct KcpIo {
    kcp: SharedKcp,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_cap: usize,
}

impl KcpIo {
    pub fn new(kcp: SharedKcp) -> KcpIo {
        let mtu = kcp.mtu();
        trace!("[INIT] KcpIo mtu {}", mtu);
        let mut buf = Vec::with_capacity(mtu);
        unsafe {
            buf.set_len(mtu);
        }

        KcpIo {
            kcp: kcp,
            read_buf: buf,
            read_pos: 0,
            read_cap: 0,
        }
    }

    /// Call everytime you got data from transmission
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        self.kcp.input(buf).map_err(From::from)
    }

    /// MTU
    pub fn mtu(&self) -> usize {
        self.kcp.mtu()
    }

    /// Shutdown
    pub fn shutdown(&mut self) -> io::Result<()> {
        self.kcp.close();
        Ok(())
    }

    /// Check if can read
    pub fn can_read(&self) -> bool {
        self.kcp.can_read()
    }
}

impl BufRead for KcpIo {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        if self.read_pos >= self.read_cap {
            loop {
                let n = match self.kcp.recv(&mut self.read_buf) {
                    Ok(n) => n,
                    Err(KcpError::UserBufTooSmall) => {
                        let orig = self.read_buf.len();
                        let incr = self.kcp.peeksize().next_power_of_two();
                        trace!("[RECV] kcp.recv buf too small, {} -> {}", orig, incr);
                        self.read_buf.resize(incr, 0);
                        continue;
                    }
                    Err(err) => {
                        return Err(From::from(err));
                    }
                };

                self.read_pos = 0;
                self.read_cap = n;

                if n != 0 {
                    let buf = &self.read_buf[..n];
                    trace!("[RECV] kcp.recv size={} conv={} {:?}", n, get_conv(buf), ::debug::BsDebug(&buf));
                }

                break;
            }
        }

        Ok(&self.read_buf[self.read_pos..self.read_cap])
    }

    fn consume(&mut self, amt: usize) {
        self.read_pos = cmp::min(self.read_cap, self.read_pos + amt);
    }
}

impl Read for KcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = self.fill_buf()?;
            available.read(buf)?
        };
        self.consume(nread);
        trace!("[RECV] KcpIo.read size={}", nread);
        Ok(nread)
    }
}

impl Write for KcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        trace!("[SEND] KcpIo.write size={} {:?}", buf.len(), ::debug::BsDebug(buf));
        let n = self.kcp.send(buf)?;
        trace!("[SEND] kcp.send size={}", n);
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.kcp.flush()?;
        trace!("[SEND] Flushed KCP buffer");
        Ok(())
    }
}

impl Drop for KcpIo {
    fn drop(&mut self) {
        self.kcp.close()
    }
}

/// Io object for client
///
/// It doesn't need to have evented to be implemented
pub struct ClientKcpIo {
    io: KcpIo,
}

impl ClientKcpIo {
    pub fn new(kcp: SharedKcp, addr: SocketAddr, expire_dur: Duration, handle: &Handle) -> io::Result<ClientKcpIo> {
        let mut sess = KcpSession::new(kcp.clone(), addr, expire_dur, handle, KcpSessionMode::Client)?;
        sess.update()?; // Call update once it is created
        let sess = Rc::new(RefCell::new(sess));
        let sess = KcpClientSession::new(sess);
        handle.spawn(sess.for_each(|_| Ok(())).map_err(|err| {
                                                           error!("Failed to update KCP session: err: {:?}", err);
                                                       }));
        trace!("[CLIENT] Created stream bind addr={}", addr);
        Ok(ClientKcpIo { io: KcpIo::new(kcp) })
    }

    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        self.io.input(buf)
    }

    pub fn mtu(&self) -> usize {
        self.io.mtu()
    }
}

impl Read for ClientKcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl Write for ClientKcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

/// Io object for server
///
/// It implements `Evented` apis
pub struct ServerKcpIo {
    io: KcpIo,
    reg: Registration,
    readiness: SetReadiness,
}

impl ServerKcpIo {
    pub fn new(kcp: SharedKcp,
               addr: SocketAddr,
               expire_dur: Duration,
               handle: &Handle,
               u: &mut KcpSessionUpdater)
               -> io::Result<ServerKcpIo> {
        let sess = KcpSession::new_shared(kcp.clone(), addr, expire_dur, handle, KcpSessionMode::Server)?;
        let (reg, r) = Registration::new2();
        let sess = KcpServerSession::new(sess, r.clone());
        u.insert_by_conv(kcp.conv(), sess);

        Ok(ServerKcpIo {
               io: KcpIo::new(kcp),
               reg: reg,
               readiness: r,
           })
    }

    /// Call everytime you got data from transmission
    pub fn input(&mut self, data: &[u8]) -> io::Result<()> {
        self.io.input(data)?;
        if self.io.can_read() {
            self.readiness.set_readiness(Ready::readable())?;
        }
        Ok(())
    }

    /// Close it
    pub fn shutdown(&mut self) -> io::Result<()> {
        self.io.shutdown()
    }
}

impl Evented for ServerKcpIo {
    fn register(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.reg.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.reg.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        <Registration as Evented>::deregister(&self.reg, poll)
    }
}

impl Read for ServerKcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl Write for ServerKcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

// impl KcpIo {
//     pub fn new(shared_kcp: SharedKcp,
//                addr: SocketAddr,
//                handle: &Handle,
//                owner: Option<KcpSessionUpdater>,
//                expire_dur: Duration)
//                -> io::Result<KcpIo> {
//         let (registration, readiness) = Registration::new2();
//         let timer = Timeout::new_at(Instant::now(), handle)?;

//         let elapsed = Rc::new(RefCell::new(Instant::now()));
//         let close_flag = Rc::new(RefCell::new(false));
//         let session = SharedKcpSession::new(shared_kcp.clone(),
//                                             timer,
//                                             elapsed.clone(),
//                                             readiness.clone(),
//                                             addr,
//                                             owner,
//                                             close_flag.clone(),
//                                             expire_dur)?;
//         handle.spawn(session.for_each(|_| Ok(())).map_err(|err| {
//                                                               error!("Failed to update KCP session: err: {:?}", err);
//                                                           }));

//         Ok(KcpIo {
//                kcp: shared_kcp,
//                registration: registration,
//                readiness: readiness,
//                last_update: elapsed,
//                close_flag: close_flag,
//                read_buf: vec![0u8; 65535],
//                read_pos: 0,
//                read_cap: 0,
//            })
//     }

//     pub fn input_buf(&mut self, buf: &[u8]) -> io::Result<()> {
//         {
//             let mut last_update = self.last_update.borrow_mut();
//             *last_update = Instant::now();
//             let mut kcp = self.kcp.borrow_mut();
//             kcp.input(buf)?;
//             trace!("[INPUT] KcpIo.input size={}", buf.len());
//         }
//         self.set_readable()
//     }

//     fn set_readable(&mut self) -> io::Result<()> {
//         self.readiness.set_readiness(Ready::readable())
//     }

//     pub fn can_read(&self) -> io::Result<bool> {
//         let kcp = self.kcp.borrow();
//         kcp.peeksize().map(|n| n != 0)
//     }
// }

// impl Evented for KcpIo {
//     fn register(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
//         self.registration.register(poll, token, interest, opts)
//     }

//     fn reregister(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
//         self.registration.reregister(poll, token, interest, opts)
//     }

//     fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
//         <Registration as Evented>::deregister(&self.registration, poll)
//     }
// }
<commit_msg>Removed invalid log<commit_after>use std::cell::RefCell;
use std::cmp;
use std::io::{self, BufRead, Read, Write};
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Duration;

use futures::{Future, Stream};
use kcp::Error as KcpError;
use mio::{self, Evented, PollOpt, Ready, Registration, SetReadiness, Token};
use tokio_core::reactor::Handle;

use session::{KcpClientSession, KcpServerSession, KcpSession, KcpSessionMode, KcpSessionUpdater};
use skcp::SharedKcp;

/// Base Io object for KCP
struct KcpIo {
    kcp: SharedKcp,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_cap: usize,
}

impl KcpIo {
    pub fn new(kcp: SharedKcp) -> KcpIo {
        let mtu = kcp.mtu();
        trace!("[INIT] KcpIo mtu {}", mtu);
        let mut buf = Vec::with_capacity(mtu);
        unsafe {
            buf.set_len(mtu);
        }

        KcpIo {
            kcp: kcp,
            read_buf: buf,
            read_pos: 0,
            read_cap: 0,
        }
    }

    /// Call everytime you got data from transmission
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        self.kcp.input(buf).map_err(From::from)
    }

    /// MTU
    pub fn mtu(&self) -> usize {
        self.kcp.mtu()
    }

    /// Shutdown
    pub fn shutdown(&mut self) -> io::Result<()> {
        self.kcp.close();
        Ok(())
    }

    /// Check if can read
    pub fn can_read(&self) -> bool {
        self.kcp.can_read()
    }
}

impl BufRead for KcpIo {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        if self.read_pos >= self.read_cap {
            loop {
                let n = match self.kcp.recv(&mut self.read_buf) {
                    Ok(n) => n,
                    Err(KcpError::UserBufTooSmall) => {
                        let orig = self.read_buf.len();
                        let incr = self.kcp.peeksize().next_power_of_two();
                        trace!("[RECV] kcp.recv buf too small, {} -> {}", orig, incr);
                        self.read_buf.resize(incr, 0);
                        continue;
                    }
                    Err(err) => {
                        return Err(From::from(err));
                    }
                };

                self.read_pos = 0;
                self.read_cap = n;

                trace!("[RECV] kcp.recv size={} {:?}", n, ::debug::BsDebug(&self.read_buf[..n]));

                break;
            }
        }

        Ok(&self.read_buf[self.read_pos..self.read_cap])
    }

    fn consume(&mut self, amt: usize) {
        self.read_pos = cmp::min(self.read_cap, self.read_pos + amt);
    }
}

impl Read for KcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = self.fill_buf()?;
            available.read(buf)?
        };
        self.consume(nread);
        trace!("[RECV] KcpIo.read size={}", nread);
        Ok(nread)
    }
}

impl Write for KcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        trace!("[SEND] KcpIo.write size={} {:?}", buf.len(), ::debug::BsDebug(buf));
        let n = self.kcp.send(buf)?;
        trace!("[SEND] kcp.send size={}", n);
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.kcp.flush()?;
        trace!("[SEND] Flushed KCP buffer");
        Ok(())
    }
}

impl Drop for KcpIo {
    fn drop(&mut self) {
        self.kcp.close()
    }
}

/// Io object for client
///
/// It doesn't need to have evented to be implemented
pub struct ClientKcpIo {
    io: KcpIo,
}

impl ClientKcpIo {
    pub fn new(kcp: SharedKcp, addr: SocketAddr, expire_dur: Duration, handle: &Handle) -> io::Result<ClientKcpIo> {
        let mut sess = KcpSession::new(kcp.clone(), addr, expire_dur, handle, KcpSessionMode::Client)?;
        sess.update()?; // Call update once it is created
        let sess = Rc::new(RefCell::new(sess));
        let sess = KcpClientSession::new(sess);
        handle.spawn(sess.for_each(|_| Ok(())).map_err(|err| {
                                                           error!("Failed to update KCP session: err: {:?}", err);
                                                       }));
        trace!("[CLIENT] Created stream bind addr={}", addr);
        Ok(ClientKcpIo { io: KcpIo::new(kcp) })
    }

    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        self.io.input(buf)
    }

    pub fn mtu(&self) -> usize {
        self.io.mtu()
    }
}

impl Read for ClientKcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl Write for ClientKcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

/// Io object for server
///
/// It implements `Evented` apis
pub struct ServerKcpIo {
    io: KcpIo,
    reg: Registration,
    readiness: SetReadiness,
}

impl ServerKcpIo {
    pub fn new(kcp: SharedKcp,
               addr: SocketAddr,
               expire_dur: Duration,
               handle: &Handle,
               u: &mut KcpSessionUpdater)
               -> io::Result<ServerKcpIo> {
        let sess = KcpSession::new_shared(kcp.clone(), addr, expire_dur, handle, KcpSessionMode::Server)?;
        let (reg, r) = Registration::new2();
        let sess = KcpServerSession::new(sess, r.clone());
        u.insert_by_conv(kcp.conv(), sess);

        Ok(ServerKcpIo {
               io: KcpIo::new(kcp),
               reg: reg,
               readiness: r,
           })
    }

    /// Call everytime you got data from transmission
    pub fn input(&mut self, data: &[u8]) -> io::Result<()> {
        self.io.input(data)?;
        if self.io.can_read() {
            self.readiness.set_readiness(Ready::readable())?;
        }
        Ok(())
    }

    /// Close it
    pub fn shutdown(&mut self) -> io::Result<()> {
        self.io.shutdown()
    }
}

impl Evented for ServerKcpIo {
    fn register(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.reg.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.reg.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        <Registration as Evented>::deregister(&self.reg, poll)
    }
}

impl Read for ServerKcpIo {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl Write for ServerKcpIo {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

// impl KcpIo {
//     pub fn new(shared_kcp: SharedKcp,
//                addr: SocketAddr,
//                handle: &Handle,
//                owner: Option<KcpSessionUpdater>,
//                expire_dur: Duration)
//                -> io::Result<KcpIo> {
//         let (registration, readiness) = Registration::new2();
//         let timer = Timeout::new_at(Instant::now(), handle)?;

//         let elapsed = Rc::new(RefCell::new(Instant::now()));
//         let close_flag = Rc::new(RefCell::new(false));
//         let session = SharedKcpSession::new(shared_kcp.clone(),
//                                             timer,
//                                             elapsed.clone(),
//                                             readiness.clone(),
//                                             addr,
//                                             owner,
//                                             close_flag.clone(),
//                                             expire_dur)?;
//         handle.spawn(session.for_each(|_| Ok(())).map_err(|err| {
//                                                               error!("Failed to update KCP session: err: {:?}", err);
//                                                           }));

//         Ok(KcpIo {
//                kcp: shared_kcp,
//                registration: registration,
//                readiness: readiness,
//                last_update: elapsed,
//                close_flag: close_flag,
//                read_buf: vec![0u8; 65535],
//                read_pos: 0,
//                read_cap: 0,
//            })
//     }

//     pub fn input_buf(&mut self, buf: &[u8]) -> io::Result<()> {
//         {
//             let mut last_update = self.last_update.borrow_mut();
//             *last_update = Instant::now();
//             let mut kcp = self.kcp.borrow_mut();
//             kcp.input(buf)?;
//             trace!("[INPUT] KcpIo.input size={}", buf.len());
//         }
//         self.set_readable()
//     }

//     fn set_readable(&mut self) -> io::Result<()> {
//         self.readiness.set_readiness(Ready::readable())
//     }

//     pub fn can_read(&self) -> io::Result<bool> {
//         let kcp = self.kcp.borrow();
//         kcp.peeksize().map(|n| n != 0)
//     }
// }

// impl Evented for KcpIo {
//     fn register(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
//         self.registration.register(poll, token, interest, opts)
//     }

//     fn reregister(&self, poll: &mio::Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
//         self.registration.reregister(poll, token, interest, opts)
//     }

//     fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
//         <Registration as Evented>::deregister(&self.registration, poll)
//     }
// }
<|endoftext|>


<commit_before>//! `i386` intrinsics

mod eflags;
pub use self::eflags::*;

#[cfg(dont_compile_me)] // TODO: need to upstream `fxsr` target feature
mod fxsr;
#[cfg(dont_compile_me)] // TODO: need to upstream `fxsr` target feature
pub use self::fxsr::*;

mod bswap;
pub use self::bswap::*;

mod rdtsc;
pub use self::rdtsc::*;

<commit_msg>remove spurious newline<commit_after>//! `i386` intrinsics

mod eflags;
pub use self::eflags::*;

#[cfg(dont_compile_me)] // TODO: need to upstream `fxsr` target feature
mod fxsr;
#[cfg(dont_compile_me)] // TODO: need to upstream `fxsr` target feature
pub use self::fxsr::*;

mod bswap;
pub use self::bswap::*;

mod rdtsc;
pub use self::rdtsc::*;
<|endoftext|>


<commit_before>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

#[cfg(unix)]
extern crate unix_socket;
#[macro_use]
extern crate quick_error;
extern crate chrono;
extern crate getopts;
extern crate uucore;

use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;
use getopts::{Matches, Options};
use std::fs::{metadata, File};
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use quick_error::ResultExt;
use std::convert::From;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;
static STRING_HEADER_OPTION: &str = "h";
static NUMBERING_MODE_OPTION: &str = "n";
static FILE_STDIN: &str = "-";
static READ_BUFFER_SIZE: usize = 1024 * 64;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    line_separator: String,
    last_modified_time: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

enum InputType {
    Directory,
    File,
    StdIn,
    SymLink,
    #[cfg(unix)]
    BlockDevice,
    #[cfg(unix)]
    CharacterDevice,
    #[cfg(unix)]
    Fifo,
    #[cfg(unix)]
    Socket,
}

impl From<Error> for PrError {
    fn from(err: Error) -> Self {
        PrError::EncounteredErrors(err.to_string())
    }
}

quick_error! {
    #[derive(Debug)]
    enum PrError {
        Input(err: Error, path: String) {
            context(path: &'a str, err: Error) -> (err, path.to_owned())
            display("pr: Reading from input {0} gave error", path)
            cause(err)
        }

        UnknownFiletype(path: String) {
            display("pr: {0}: unknown filetype", path)
        }

        EncounteredErrors(msg: String) {
            display("pr: {0} encountered", msg)
        }

        IsDirectory(path: String) {
            display("pr: {0}: Is a directory", path)
        }

        IsSocket(path: String) {
            display("pr: cannot open {}, Operation not supported on socket", path)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        STRING_HEADER_OPTION,
        "",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflag(
        "d",
        "",
        "Produce output that is double spaced. An extra <newline> character is output following every <newline>
           found in the input.",
    );

    opts.optflagopt(
        NUMBERING_MODE_OPTION,
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut files: Vec<String> = matches.free.clone();
    if files.is_empty() {
        //For stdin
        files.push(FILE_STDIN.to_owned());
    }

    if matches.opt_present("help") {
        return print_usage(&mut opts, &matches);
    }

    for f in files {
        let header: &String = &matches.opt_str(STRING_HEADER_OPTION).unwrap_or(f.to_string());
        let options: &OutputOptions = &build_options(&matches, header, &f);
        let status: i32 = match pr(&f, options) {
            Err(error) => {
                writeln!(&mut stderr(), "{}", error);
                -1
            },
            _ => 0
        };
        if status != 0 {
            return status;
        }
    }
    return 0;
}

fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
    println!("{} {} -- print files", NAME, VERSION);
    println!();
    println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
    println!();
    let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
    println!("{}", opts.usage(usage));
    if matches.free.is_empty() {
        return 1;
    }
    return 0;
}

fn build_options(matches: &Matches, header: &String, path: &String) -> OutputOptions {
    let numbering_options: Option<NumberingMode> = matches.opt_str(NUMBERING_MODE_OPTION).map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present(NUMBERING_MODE_OPTION) {
            return Some(NumberingMode::default());
        }
        return None;
    });

    let line_separator: String = if matches.opt_present("d") {
        "\n\n".to_string()
    } else {
        "\n".to_string()
    };

    let last_modified_time = if path.eq(FILE_STDIN) {
        current_time()
    } else {
        file_last_modified_time(path)
    };

    OutputOptions {
        number: numbering_options,
        header: header.to_string(),
        line_separator,
        last_modified_time,
    }
}

fn open(path: &str) -> Result<Box<Read>, PrError> {
    match get_input_type(path) {
        Some(InputType::Directory) => Err(PrError::IsDirectory(path.to_string())),
        #[cfg(unix)]
        Some(InputType::Socket) => {
            Err(PrError::IsSocket(path.to_string()))
        }
        Some(InputType::StdIn) => {
            let stdin = stdin();
            Ok(Box::new(stdin) as Box<Read>)
        }
        Some(_) => Ok(Box::new(File::open(path).context(path)?) as Box<Read>),
        None => Err(PrError::UnknownFiletype(path.to_string()))
    }
}

fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();

    for line in BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines() {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            print_page(&buffered_content, options, &page)?;
            buffered_content = Vec::new();
        }
        buffered_content.push(line?);
        i = i + 1;
    }

    if i != 0 {
        page = page + 1;
        print_page(&buffered_content, options, &page)?;
    }
    return Ok(0);
}

fn print_page(lines: &Vec<String>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
    let header: Vec<String> = header_content(options, page);
    let trailer_content: Vec<String> = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE);
    assert_eq!(header.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE);
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE);
    let out: &mut Stdout = &mut stdout();
    let line_separator = options.as_ref().line_separator.as_bytes();
    let mut lines_written = 0;

    out.lock();
    for x in header {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            out.write(x.as_bytes())?;
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(&width, prev_lines + i, &separator);
            out.write(format!("{}{}", fmtd_line_number, x).as_bytes())?;
        }
        out.write(line_separator)?;
        i = i + 1;
    }
    lines_written += i - 1;
    for x in trailer_content {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }
    out.flush()?;
    Ok(lines_written)
}

fn get_fmtd_line_number(width: &usize, line_number: usize, separator: &String) -> String {
    let line_str = line_number.to_string();
    if line_str.len() >= *width {
        format!("{:>width$}{}", &line_str[line_str.len() - *width..], separator, width = width)
    } else {
        format!("{:>width$}{}", line_str, separator, width = width)
    }
}

fn header_content(options: &OutputOptions, page: &usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", options.last_modified_time, options.header, page);
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn current_time() -> String {
    let datetime: DateTime<Local> = Local::now();
    datetime.format("%b %d %H:%M %Y").to_string()
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}

fn get_input_type(path: &str) -> Option<InputType> {
    if path == FILE_STDIN {
        return Some(InputType::StdIn);
    }

    metadata(path).map(|i| {
        match i.file_type() {
            #[cfg(unix)]
            ft if ft.is_block_device() =>
                {
                    Some(InputType::BlockDevice)
                }
            #[cfg(unix)]
            ft if ft.is_char_device() =>
                {
                    Some(InputType::CharacterDevice)
                }
            #[cfg(unix)]
            ft if ft.is_fifo() =>
                {
                    Some(InputType::Fifo)
                }
            #[cfg(unix)]
            ft if ft.is_socket() =>
                {
                    Some(InputType::Socket)
                }
            ft if ft.is_dir() => Some(InputType::Directory),
            ft if ft.is_file() => Some(InputType::File),
            ft if ft.is_symlink() => Some(InputType::SymLink),
            _ => None
        }
    }).unwrap_or(None)
}
<commit_msg>pr: add long names for -d and -h<commit_after>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

#[cfg(unix)]
extern crate unix_socket;
#[macro_use]
extern crate quick_error;
extern crate chrono;
extern crate getopts;
extern crate uucore;

use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;
use getopts::{Matches, Options};
use std::fs::{metadata, File};
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use quick_error::ResultExt;
use std::convert::From;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;
static STRING_HEADER_OPTION: &str = "h";
static DOUBLE_SPACE_OPTION: &str = "d";
static NUMBERING_MODE_OPTION: &str = "n";
static FILE_STDIN: &str = "-";
static READ_BUFFER_SIZE: usize = 1024 * 64;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    line_separator: String,
    last_modified_time: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

enum InputType {
    Directory,
    File,
    StdIn,
    SymLink,
    #[cfg(unix)]
    BlockDevice,
    #[cfg(unix)]
    CharacterDevice,
    #[cfg(unix)]
    Fifo,
    #[cfg(unix)]
    Socket,
}

impl From<Error> for PrError {
    fn from(err: Error) -> Self {
        PrError::EncounteredErrors(err.to_string())
    }
}

quick_error! {
    #[derive(Debug)]
    enum PrError {
        Input(err: Error, path: String) {
            context(path: &'a str, err: Error) -> (err, path.to_owned())
            display("pr: Reading from input {0} gave error", path)
            cause(err)
        }

        UnknownFiletype(path: String) {
            display("pr: {0}: unknown filetype", path)
        }

        EncounteredErrors(msg: String) {
            display("pr: {0} encountered", msg)
        }

        IsDirectory(path: String) {
            display("pr: {0}: Is a directory", path)
        }

        IsSocket(path: String) {
            display("pr: cannot open {}, Operation not supported on socket", path)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        STRING_HEADER_OPTION,
        "header",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflag(
        DOUBLE_SPACE_OPTION,
        "double-space",
        "Produce output that is double spaced. An extra <newline> character is output following every <newline>
           found in the input.",
    );

    opts.optflagopt(
        NUMBERING_MODE_OPTION,
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut files: Vec<String> = matches.free.clone();
    if files.is_empty() {
        //For stdin
        files.push(FILE_STDIN.to_owned());
    }

    if matches.opt_present("help") {
        return print_usage(&mut opts, &matches);
    }

    for f in files {
        let header: &String = &matches.opt_str(STRING_HEADER_OPTION).unwrap_or(f.to_string());
        let options: &OutputOptions = &build_options(&matches, header, &f);
        let status: i32 = match pr(&f, options) {
            Err(error) => {
                writeln!(&mut stderr(), "{}", error);
                -1
            },
            _ => 0
        };
        if status != 0 {
            return status;
        }
    }
    return 0;
}

fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
    println!("{} {} -- print files", NAME, VERSION);
    println!();
    println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
    println!();
    let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
    println!("{}", opts.usage(usage));
    if matches.free.is_empty() {
        return 1;
    }
    return 0;
}

fn build_options(matches: &Matches, header: &String, path: &String) -> OutputOptions {
    let numbering_options: Option<NumberingMode> = matches.opt_str(NUMBERING_MODE_OPTION).map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present(NUMBERING_MODE_OPTION) {
            return Some(NumberingMode::default());
        }
        return None;
    });

    let line_separator: String = if matches.opt_present("d") {
        "\n\n".to_string()
    } else {
        "\n".to_string()
    };

    let last_modified_time = if path.eq(FILE_STDIN) {
        current_time()
    } else {
        file_last_modified_time(path)
    };

    OutputOptions {
        number: numbering_options,
        header: header.to_string(),
        line_separator,
        last_modified_time,
    }
}

fn open(path: &str) -> Result<Box<Read>, PrError> {
    match get_input_type(path) {
        Some(InputType::Directory) => Err(PrError::IsDirectory(path.to_string())),
        #[cfg(unix)]
        Some(InputType::Socket) => {
            Err(PrError::IsSocket(path.to_string()))
        }
        Some(InputType::StdIn) => {
            let stdin = stdin();
            Ok(Box::new(stdin) as Box<Read>)
        }
        Some(_) => Ok(Box::new(File::open(path).context(path)?) as Box<Read>),
        None => Err(PrError::UnknownFiletype(path.to_string()))
    }
}

fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();

    for line in BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines() {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            print_page(&buffered_content, options, &page)?;
            buffered_content = Vec::new();
        }
        buffered_content.push(line?);
        i = i + 1;
    }

    if i != 0 {
        page = page + 1;
        print_page(&buffered_content, options, &page)?;
    }
    return Ok(0);
}

fn print_page(lines: &Vec<String>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
    let header: Vec<String> = header_content(options, page);
    let trailer_content: Vec<String> = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE);
    assert_eq!(header.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE);
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE);
    let out: &mut Stdout = &mut stdout();
    let line_separator = options.as_ref().line_separator.as_bytes();
    let mut lines_written = 0;

    out.lock();
    for x in header {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            out.write(x.as_bytes())?;
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(&width, prev_lines + i, &separator);
            out.write(format!("{}{}", fmtd_line_number, x).as_bytes())?;
        }
        out.write(line_separator)?;
        i = i + 1;
    }
    lines_written += i - 1;
    for x in trailer_content {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }
    out.flush()?;
    Ok(lines_written)
}

fn get_fmtd_line_number(width: &usize, line_number: usize, separator: &String) -> String {
    let line_str = line_number.to_string();
    if line_str.len() >= *width {
        format!("{:>width$}{}", &line_str[line_str.len() - *width..], separator, width = width)
    } else {
        format!("{:>width$}{}", line_str, separator, width = width)
    }
}

fn header_content(options: &OutputOptions, page: &usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", options.last_modified_time, options.header, page);
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn current_time() -> String {
    let datetime: DateTime<Local> = Local::now();
    datetime.format("%b %d %H:%M %Y").to_string()
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}

fn get_input_type(path: &str) -> Option<InputType> {
    if path == FILE_STDIN {
        return Some(InputType::StdIn);
    }

    metadata(path).map(|i| {
        match i.file_type() {
            #[cfg(unix)]
            ft if ft.is_block_device() =>
                {
                    Some(InputType::BlockDevice)
                }
            #[cfg(unix)]
            ft if ft.is_char_device() =>
                {
                    Some(InputType::CharacterDevice)
                }
            #[cfg(unix)]
            ft if ft.is_fifo() =>
                {
                    Some(InputType::Fifo)
                }
            #[cfg(unix)]
            ft if ft.is_socket() =>
                {
                    Some(InputType::Socket)
                }
            ft if ft.is_dir() => Some(InputType::Directory),
            ft if ft.is_file() => Some(InputType::File),
            ft if ft.is_symlink() => Some(InputType::SymLink),
            _ => None
        }
    }).unwrap_or(None)
}
<|endoftext|>


<commit_before>use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0u, 0, 0];
/// let ys = [69u, 107, 101];
///
/// for (i, a, b) in Zip::new((range(0, 100u), xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T>
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

// Macro to turn `t.$idx`, where $idx:tt, into an expression.
macro_rules! e(
    ($e:expr) => { $e }
);

macro_rules! impl_zip_iter(
    ($($idx:tt is $B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                $(
                    let $B = match e!(self.t. $idx).next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (uint, Option<uint>)
            {
                let mut low = ::std::uint::MAX;
                let mut high = None;
                $(
                    // update estimate
                    let (l, h) = e!(self.t. $idx).size_hint();
                    low = cmp::min(low, l);
                    high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
);

impl_zip_iter!(0 is A);
impl_zip_iter!(0 is A, 1 is B);
impl_zip_iter!(0 is A, 1 is B, 2 is C);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H, 8 is I);
<commit_msg>Add trait bound to Zip::new<commit_after>use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0u, 0, 0];
/// let ys = [69u, 107, 101];
///
/// for (i, a, b) in Zip::new((range(0, 100u), xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T> where Zip<T>: Iterator
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

// Macro to turn `t.$idx`, where $idx:tt, into an expression.
macro_rules! e(
    ($e:expr) => { $e }
);

macro_rules! impl_zip_iter(
    ($($idx:tt is $B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                $(
                    let $B = match e!(self.t. $idx).next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (uint, Option<uint>)
            {
                let mut low = ::std::uint::MAX;
                let mut high = None;
                $(
                    // update estimate
                    let (l, h) = e!(self.t. $idx).size_hint();
                    low = cmp::min(low, l);
                    high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
);

impl_zip_iter!(0 is A);
impl_zip_iter!(0 is A, 1 is B);
impl_zip_iter!(0 is A, 1 is B, 2 is C);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H);
impl_zip_iter!(0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H, 8 is I);
<|endoftext|>