<commit_before>use super::{generate_deterministic_keypairs, KeypairsFile};
use crate::test_utils::TestingPendingAttestationBuilder;
use crate::*;
use bls::get_withdrawal_credentials;
use dirs;
use log::debug;
use rayon::prelude::*;
use std::path::{Path, PathBuf};

pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs";

/// Returns the directory where the generated keypairs should be stored.
///
/// It is either `$HOME/.lighthouse/keypairs.raw_keypairs` or, if `$HOME` is not available,
/// `./keypairs.raw_keypairs`.
pub fn keypairs_path() -> PathBuf {
    let dir = dirs::home_dir()
        .and_then(|home| Some(home.join(".lighthouse")))
        .unwrap_or_else(|| PathBuf::from(""));
    dir.join(KEYPAIRS_FILE)
}

/// Builds a beacon state to be used for testing purposes.
///
/// This struct should **never be used for production purposes.**
#[derive(Clone)]
pub struct TestingBeaconStateBuilder {
    state: BeaconState,
    keypairs: Vec<Keypair>,
}

impl TestingBeaconStateBuilder {
    /// Attempts to load validators from a file in `$HOME/.lighthouse/keypairs.raw_keypairs`. If
    /// the file is unavailable, it generates the keys at runtime.
    ///
    /// If the `$HOME` environment variable is not set, the local directory is used.
    ///
    /// See the `Self::from_keypairs_file` method for more info.
    ///
    /// # Panics
    ///
    /// If the file does not contain enough keypairs or is invalid.
    pub fn from_default_keypairs_file_if_exists(validator_count: usize, spec: &ChainSpec) -> Self {
        let dir = dirs::home_dir()
            .and_then(|home| Some(home.join(".lighthouse")))
            .unwrap_or_else(|| PathBuf::from(""));
        let file = dir.join(KEYPAIRS_FILE);

        if file.exists() {
            TestingBeaconStateBuilder::from_keypairs_file(validator_count, &file, spec)
        } else {
            TestingBeaconStateBuilder::from_deterministic_keypairs(validator_count, spec)
        }
    }

    /// Loads the initial validator keypairs from a file on disk.
    ///
    /// Loading keypairs from file is ~10x faster than generating them. Use the `gen_keys` command
    /// on the  `test_harness` binary to generate the keys. In the `test_harness` dir, run `cargo
    /// run -- gen_keys -h` for help.
    ///
    /// # Panics
    ///
    /// If the file does not exist, is invalid or does not contain enough keypairs.
    pub fn from_keypairs_file(validator_count: usize, path: &Path, spec: &ChainSpec) -> Self {
        debug!("Loading {} keypairs from file...", validator_count);
        let keypairs = Vec::from_raw_file(path, validator_count).unwrap();
        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Generates the validator keypairs deterministically.
    pub fn from_deterministic_keypairs(validator_count: usize, spec: &ChainSpec) -> Self {
        debug!("Generating {} deterministic keypairs...", validator_count);
        let keypairs = generate_deterministic_keypairs(validator_count);
        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Uses the given keypair for all validators.
    pub fn from_single_keypair(
        validator_count: usize,
        keypair: &Keypair,
        spec: &ChainSpec,
    ) -> Self {
        debug!("Generating {} cloned keypairs...", validator_count);

        let mut keypairs = Vec::with_capacity(validator_count);
        for _ in 0..validator_count {
            keypairs.push(keypair.clone())
        }

        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Creates the builder from an existing set of keypairs.
    pub fn from_keypairs(keypairs: Vec<Keypair>, spec: &ChainSpec) -> Self {
        let validator_count = keypairs.len();

        debug!(
            "Building {} Validator objects from keypairs...",
            validator_count
        );
        let validators = keypairs
            .par_iter()
            .map(|keypair| {
                let withdrawal_credentials = Hash256::from_slice(&get_withdrawal_credentials(
                    &keypair.pk,
                    spec.bls_withdrawal_prefix_byte,
                ));

                Validator {
                    pubkey: keypair.pk.clone(),
                    withdrawal_credentials,
                    // All validators start active.
                    activation_epoch: spec.genesis_epoch,
                    exit_epoch: spec.far_future_epoch,
                    withdrawable_epoch: spec.far_future_epoch,
                    initiated_exit: false,
                    slashed: false,
                }
            })
            .collect();

        let genesis_time = 1553638359; // arbitrary

        let mut state = BeaconState::genesis(
            genesis_time,
            Eth1Data {
                deposit_root: Hash256::zero(),
                block_hash: Hash256::zero(),
            },
            spec,
        );

        let balances = vec![32_000_000_000; validator_count];

        debug!("Importing {} existing validators...", validator_count);
        state.validator_registry = validators;
        state.validator_balances = balances;

        debug!("BeaconState initialized.");

        Self { state, keypairs }
    }

    /// Consume the builder and return the `BeaconState` and the keypairs for each validator.
    pub fn build(self) -> (BeaconState, Vec<Keypair>) {
        (self.state, self.keypairs)
    }

    /// Ensures that the state returned from `Self::build(..)` has all caches pre-built.
    ///
    /// Note: this performs the build when called. Ensure that no changes are made that would
    /// invalidate this cache.
    pub fn build_caches(&mut self, spec: &ChainSpec) -> Result<(), BeaconStateError> {
        let state = &mut self.state;

        state.build_epoch_cache(RelativeEpoch::Previous, &spec)?;
        state.build_epoch_cache(RelativeEpoch::Current, &spec)?;
        state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &spec)?;
        state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &spec)?;

        state.update_pubkey_cache()?;

        Ok(())
    }

    /// Sets the `BeaconState` to be in a slot, calling `teleport_to_epoch` to update the epoch.
    pub fn teleport_to_slot(&mut self, slot: Slot, spec: &ChainSpec) {
        self.teleport_to_epoch(slot.epoch(spec.slots_per_epoch), spec);
        self.state.slot = slot;
    }

    /// Sets the `BeaconState` to be in the first slot of the given epoch.
    ///
    /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
    /// highest justified and finalized slots, full justification bitfield, etc).
    fn teleport_to_epoch(&mut self, epoch: Epoch, spec: &ChainSpec) {
        let state = &mut self.state;

        let slot = epoch.start_slot(spec.slots_per_epoch);

        state.slot = slot;

        state.previous_shuffling_epoch = epoch - 1;
        state.current_shuffling_epoch = epoch;

        state.previous_shuffling_seed = Hash256::from_low_u64_le(0);
        state.current_shuffling_seed = Hash256::from_low_u64_le(1);

        state.previous_justified_epoch = epoch - 3;
        state.current_justified_epoch = epoch - 2;
        state.justification_bitfield = u64::max_value();

        state.finalized_epoch = epoch - 3;
        state.validator_registry_update_epoch = epoch - 3;
    }

    /// Creates a full set of attestations for the `BeaconState`. Each attestation has full
    /// participation from its committee and references the expected beacon_block hashes.
    ///
    /// These attestations should be fully conducive to justification and finalization.
    pub fn insert_attestations(&mut self, spec: &ChainSpec) {
        let state = &mut self.state;

        state
            .build_epoch_cache(RelativeEpoch::Previous, spec)
            .unwrap();
        state
            .build_epoch_cache(RelativeEpoch::Current, spec)
            .unwrap();

        let current_epoch = state.current_epoch(spec);
        let previous_epoch = state.previous_epoch(spec);

        let first_slot = previous_epoch.start_slot(spec.slots_per_epoch).as_u64();
        let last_slot = current_epoch.end_slot(spec.slots_per_epoch).as_u64()
            - spec.min_attestation_inclusion_delay;
        let last_slot = std::cmp::min(state.slot.as_u64(), last_slot);

        for slot in first_slot..=last_slot {
            let slot = Slot::from(slot);

            let committees = state
                .get_crosslink_committees_at_slot(slot, spec)
                .unwrap()
                .clone();

            for crosslink_committee in committees {
                let mut builder = TestingPendingAttestationBuilder::new(
                    state,
                    crosslink_committee.shard,
                    slot,
                    spec,
                );
                // The entire committee should have signed the pending attestation.
                let signers = vec![true; crosslink_committee.committee.len()];
                builder.add_committee_participation(signers);
                let attestation = builder.build();

                if attestation.data.slot.epoch(spec.slots_per_epoch) < state.current_epoch(spec) {
                    state.previous_epoch_attestations.push(attestation)
                } else {
                    state.current_epoch_attestations.push(attestation)
                }
            }
        }
    }
}
<commit_msg>Move genesis time forward<commit_after>use super::{generate_deterministic_keypairs, KeypairsFile};
use crate::test_utils::TestingPendingAttestationBuilder;
use crate::*;
use bls::get_withdrawal_credentials;
use dirs;
use log::debug;
use rayon::prelude::*;
use std::path::{Path, PathBuf};

pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs";

/// Returns the directory where the generated keypairs should be stored.
///
/// It is either `$HOME/.lighthouse/keypairs.raw_keypairs` or, if `$HOME` is not available,
/// `./keypairs.raw_keypairs`.
pub fn keypairs_path() -> PathBuf {
    let dir = dirs::home_dir()
        .and_then(|home| Some(home.join(".lighthouse")))
        .unwrap_or_else(|| PathBuf::from(""));
    dir.join(KEYPAIRS_FILE)
}

/// Builds a beacon state to be used for testing purposes.
///
/// This struct should **never be used for production purposes.**
#[derive(Clone)]
pub struct TestingBeaconStateBuilder {
    state: BeaconState,
    keypairs: Vec<Keypair>,
}

impl TestingBeaconStateBuilder {
    /// Attempts to load validators from a file in `$HOME/.lighthouse/keypairs.raw_keypairs`. If
    /// the file is unavailable, it generates the keys at runtime.
    ///
    /// If the `$HOME` environment variable is not set, the local directory is used.
    ///
    /// See the `Self::from_keypairs_file` method for more info.
    ///
    /// # Panics
    ///
    /// If the file does not contain enough keypairs or is invalid.
    pub fn from_default_keypairs_file_if_exists(validator_count: usize, spec: &ChainSpec) -> Self {
        let dir = dirs::home_dir()
            .and_then(|home| Some(home.join(".lighthouse")))
            .unwrap_or_else(|| PathBuf::from(""));
        let file = dir.join(KEYPAIRS_FILE);

        if file.exists() {
            TestingBeaconStateBuilder::from_keypairs_file(validator_count, &file, spec)
        } else {
            TestingBeaconStateBuilder::from_deterministic_keypairs(validator_count, spec)
        }
    }

    /// Loads the initial validator keypairs from a file on disk.
    ///
    /// Loading keypairs from file is ~10x faster than generating them. Use the `gen_keys` command
    /// on the  `test_harness` binary to generate the keys. In the `test_harness` dir, run `cargo
    /// run -- gen_keys -h` for help.
    ///
    /// # Panics
    ///
    /// If the file does not exist, is invalid or does not contain enough keypairs.
    pub fn from_keypairs_file(validator_count: usize, path: &Path, spec: &ChainSpec) -> Self {
        debug!("Loading {} keypairs from file...", validator_count);
        let keypairs = Vec::from_raw_file(path, validator_count).unwrap();
        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Generates the validator keypairs deterministically.
    pub fn from_deterministic_keypairs(validator_count: usize, spec: &ChainSpec) -> Self {
        debug!("Generating {} deterministic keypairs...", validator_count);
        let keypairs = generate_deterministic_keypairs(validator_count);
        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Uses the given keypair for all validators.
    pub fn from_single_keypair(
        validator_count: usize,
        keypair: &Keypair,
        spec: &ChainSpec,
    ) -> Self {
        debug!("Generating {} cloned keypairs...", validator_count);

        let mut keypairs = Vec::with_capacity(validator_count);
        for _ in 0..validator_count {
            keypairs.push(keypair.clone())
        }

        TestingBeaconStateBuilder::from_keypairs(keypairs, spec)
    }

    /// Creates the builder from an existing set of keypairs.
    pub fn from_keypairs(keypairs: Vec<Keypair>, spec: &ChainSpec) -> Self {
        let validator_count = keypairs.len();

        debug!(
            "Building {} Validator objects from keypairs...",
            validator_count
        );
        let validators = keypairs
            .par_iter()
            .map(|keypair| {
                let withdrawal_credentials = Hash256::from_slice(&get_withdrawal_credentials(
                    &keypair.pk,
                    spec.bls_withdrawal_prefix_byte,
                ));

                Validator {
                    pubkey: keypair.pk.clone(),
                    withdrawal_credentials,
                    // All validators start active.
                    activation_epoch: spec.genesis_epoch,
                    exit_epoch: spec.far_future_epoch,
                    withdrawable_epoch: spec.far_future_epoch,
                    initiated_exit: false,
                    slashed: false,
                }
            })
            .collect();

        let genesis_time = 1553647464; // arbitrary

        let mut state = BeaconState::genesis(
            genesis_time,
            Eth1Data {
                deposit_root: Hash256::zero(),
                block_hash: Hash256::zero(),
            },
            spec,
        );

        let balances = vec![32_000_000_000; validator_count];

        debug!("Importing {} existing validators...", validator_count);
        state.validator_registry = validators;
        state.validator_balances = balances;

        debug!("BeaconState initialized.");

        Self { state, keypairs }
    }

    /// Consume the builder and return the `BeaconState` and the keypairs for each validator.
    pub fn build(self) -> (BeaconState, Vec<Keypair>) {
        (self.state, self.keypairs)
    }

    /// Ensures that the state returned from `Self::build(..)` has all caches pre-built.
    ///
    /// Note: this performs the build when called. Ensure that no changes are made that would
    /// invalidate this cache.
    pub fn build_caches(&mut self, spec: &ChainSpec) -> Result<(), BeaconStateError> {
        let state = &mut self.state;

        state.build_epoch_cache(RelativeEpoch::Previous, &spec)?;
        state.build_epoch_cache(RelativeEpoch::Current, &spec)?;
        state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &spec)?;
        state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &spec)?;

        state.update_pubkey_cache()?;

        Ok(())
    }

    /// Sets the `BeaconState` to be in a slot, calling `teleport_to_epoch` to update the epoch.
    pub fn teleport_to_slot(&mut self, slot: Slot, spec: &ChainSpec) {
        self.teleport_to_epoch(slot.epoch(spec.slots_per_epoch), spec);
        self.state.slot = slot;
    }

    /// Sets the `BeaconState` to be in the first slot of the given epoch.
    ///
    /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
    /// highest justified and finalized slots, full justification bitfield, etc).
    fn teleport_to_epoch(&mut self, epoch: Epoch, spec: &ChainSpec) {
        let state = &mut self.state;

        let slot = epoch.start_slot(spec.slots_per_epoch);

        state.slot = slot;

        state.previous_shuffling_epoch = epoch - 1;
        state.current_shuffling_epoch = epoch;

        state.previous_shuffling_seed = Hash256::from_low_u64_le(0);
        state.current_shuffling_seed = Hash256::from_low_u64_le(1);

        state.previous_justified_epoch = epoch - 3;
        state.current_justified_epoch = epoch - 2;
        state.justification_bitfield = u64::max_value();

        state.finalized_epoch = epoch - 3;
        state.validator_registry_update_epoch = epoch - 3;
    }

    /// Creates a full set of attestations for the `BeaconState`. Each attestation has full
    /// participation from its committee and references the expected beacon_block hashes.
    ///
    /// These attestations should be fully conducive to justification and finalization.
    pub fn insert_attestations(&mut self, spec: &ChainSpec) {
        let state = &mut self.state;

        state
            .build_epoch_cache(RelativeEpoch::Previous, spec)
            .unwrap();
        state
            .build_epoch_cache(RelativeEpoch::Current, spec)
            .unwrap();

        let current_epoch = state.current_epoch(spec);
        let previous_epoch = state.previous_epoch(spec);

        let first_slot = previous_epoch.start_slot(spec.slots_per_epoch).as_u64();
        let last_slot = current_epoch.end_slot(spec.slots_per_epoch).as_u64()
            - spec.min_attestation_inclusion_delay;
        let last_slot = std::cmp::min(state.slot.as_u64(), last_slot);

        for slot in first_slot..=last_slot {
            let slot = Slot::from(slot);

            let committees = state
                .get_crosslink_committees_at_slot(slot, spec)
                .unwrap()
                .clone();

            for crosslink_committee in committees {
                let mut builder = TestingPendingAttestationBuilder::new(
                    state,
                    crosslink_committee.shard,
                    slot,
                    spec,
                );
                // The entire committee should have signed the pending attestation.
                let signers = vec![true; crosslink_committee.committee.len()];
                builder.add_committee_participation(signers);
                let attestation = builder.build();

                if attestation.data.slot.epoch(spec.slots_per_epoch) < state.current_epoch(spec) {
                    state.previous_epoch_attestations.push(attestation)
                } else {
                    state.current_epoch_attestations.push(attestation)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc::hir;
use rustc::lint::{EarlyContext, LateContext};
use std::borrow::Cow;
use std;
use syntax::ast;
use syntax::util::parser::AssocOp;
use utils::{higher, snippet};

/// A helper type to build suggestion correctly handling parenthesis.
pub enum Sugg<'a> {
    /// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
    NonParen(Cow<'a, str>),
    /// An expression that does not fit in other variants.
    MaybeParen(Cow<'a, str>),
    /// A binary operator expression, including `as`-casts and explicit type coercion.
    BinOp(AssocOp, Cow<'a, str>),
}

impl<'a> std::fmt::Display for Sugg<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => {
                s.fmt(f)
            }
        }
    }
}

impl<'a> Sugg<'a> {
    pub fn hir(cx: &LateContext, expr: &'a hir::Expr, default: &'a str) -> Sugg<'a> {
        let snippet = snippet(cx, expr.span, default);

        match expr.node {
            hir::ExprAddrOf(..) |
            hir::ExprBox(..) |
            hir::ExprClosure(..) |
            hir::ExprIf(..) |
            hir::ExprUnary(..) |
            hir::ExprMatch(..) => Sugg::MaybeParen(snippet),
            hir::ExprAgain(..) |
            hir::ExprBlock(..) |
            hir::ExprBreak(..) |
            hir::ExprCall(..) |
            hir::ExprField(..) |
            hir::ExprIndex(..) |
            hir::ExprInlineAsm(..) |
            hir::ExprLit(..) |
            hir::ExprLoop(..) |
            hir::ExprMethodCall(..) |
            hir::ExprPath(..) |
            hir::ExprRepeat(..) |
            hir::ExprRet(..) |
            hir::ExprStruct(..) |
            hir::ExprTup(..) |
            hir::ExprTupField(..) |
            hir::ExprVec(..) |
            hir::ExprWhile(..) => Sugg::NonParen(snippet),
            hir::ExprAssign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
            hir::ExprAssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
            hir::ExprBinary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
            hir::ExprCast(..) => Sugg::BinOp(AssocOp::As, snippet),
            hir::ExprType(..) => Sugg::BinOp(AssocOp::Colon, snippet),
        }
    }

    pub fn ast(cx: &EarlyContext, expr: &'a ast::Expr, default: &'a str) -> Sugg<'a> {
        use syntax::ast::RangeLimits;

        let snippet = snippet(cx, expr.span, default);

        match expr.node {
            ast::ExprKind::AddrOf(..) |
            ast::ExprKind::Box(..) |
            ast::ExprKind::Closure(..) |
            ast::ExprKind::If(..) |
            ast::ExprKind::IfLet(..) |
            ast::ExprKind::InPlace(..) |
            ast::ExprKind::Unary(..) |
            ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
            ast::ExprKind::Again(..) |
            ast::ExprKind::Block(..) |
            ast::ExprKind::Break(..) |
            ast::ExprKind::Call(..) |
            ast::ExprKind::Field(..) |
            ast::ExprKind::ForLoop(..) |
            ast::ExprKind::Index(..) |
            ast::ExprKind::InlineAsm(..) |
            ast::ExprKind::Lit(..) |
            ast::ExprKind::Loop(..) |
            ast::ExprKind::Mac(..) |
            ast::ExprKind::MethodCall(..) |
            ast::ExprKind::Paren(..) |
            ast::ExprKind::Path(..) |
            ast::ExprKind::Repeat(..) |
            ast::ExprKind::Ret(..) |
            ast::ExprKind::Struct(..) |
            ast::ExprKind::Try(..) |
            ast::ExprKind::Tup(..) |
            ast::ExprKind::TupField(..) |
            ast::ExprKind::Vec(..) |
            ast::ExprKind::While(..) |
            ast::ExprKind::WhileLet(..) => Sugg::NonParen(snippet),
            ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
            ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotDot, snippet),
            ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
            ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
            ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
            ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
            ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
        }
    }

    /// Convenience method to create the `lhs && rhs` suggestion.
    pub fn and(&self, rhs: &Self) -> Sugg<'static> {
        make_binop(ast::BinOpKind::And, self, rhs)
    }

    /// Convenience method to create the `&<expr>` suggestion.
    pub fn addr(&self) -> Sugg<'static> {
        make_unop("&", self)
    }
}

impl<'a, 'b> std::ops::Sub<&'b Sugg<'b>> for &'a Sugg<'a> {
    type Output = Sugg<'static>;
    fn sub(self, rhs: &'b Sugg<'b>) -> Sugg<'static> {
        make_binop(ast::BinOpKind::Sub, self, rhs)
    }
}

impl<'a> std::ops::Not for &'a Sugg<'a> {
    type Output = Sugg<'static>;
    fn not(self) -> Sugg<'static> {
        make_unop("!", self)
    }
}

struct ParenHelper<T> {
    paren: bool,
    wrapped: T,
}

impl<T> ParenHelper<T> {
    fn new(paren: bool, wrapped: T) -> Self {
        ParenHelper {
            paren: paren,
            wrapped: wrapped,
        }
    }
}

impl<T: std::fmt::Display> std::fmt::Display for ParenHelper<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        if self.paren {
            write!(f, "({})", self.wrapped)
        } else {
            self.wrapped.fmt(f)
        }
    }
}

/// Build the string for `<op> <expr>` adding parenthesis when necessary.
///
/// For convenience, the operator is taken as a string because all unary operators have the same
/// precedence.
pub fn make_unop(op: &str, expr: &Sugg) -> Sugg<'static> {
    let needs_paren = !matches!(*expr, Sugg::NonParen(..));
    Sugg::MaybeParen(format!("{}{}", op, ParenHelper::new(needs_paren, expr)).into())
}

/// Build the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
///
/// Precedence of shift operator relative to other arithmetic operation is often confusing so
/// parenthesis will always be added for a mix of these.
pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
    fn is_shift(op: &AssocOp) -> bool {
        matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
    }

    fn is_arith(op: &AssocOp) -> bool {
        matches!(*op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus)
    }

    fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
        other.precedence() < op.precedence() ||
            (other.precedence() == op.precedence() &&
                ((op != other && associativity(op) != dir) ||
                 (op == other && associativity(op) != Associativity::Both))) ||
             is_shift(op) && is_arith(other) ||
             is_shift(other) && is_arith(op)
    }

    let aop = AssocOp::from_ast_binop(op);

    let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
        needs_paren(&aop, lop, Associativity::Left)
    } else {
        false
    };

    let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs {
        needs_paren(&aop, rop, Associativity::Right)
    } else {
        false
    };

    Sugg::BinOp(aop,
                format!("{} {} {}",
                        ParenHelper::new(lhs_paren, lhs),
                        op.to_string(),
                        ParenHelper::new(rhs_paren, rhs)).into())
}

#[derive(PartialEq, Eq)]
enum Associativity {
    Both,
    Left,
    None,
    Right,
}

/// Return the associativity/fixity of an operator. The difference with `AssocOp::fixity` is that
/// an operator can be both left and right associative (such as `+`:
/// `a + b + c == (a + b) + c == a + (b + c)`.
///
/// Chained `as` and explicit `:` type coercion never need inner parenthesis so they are considered
/// associative.
fn associativity(op: &AssocOp) -> Associativity {
    use syntax::util::parser::AssocOp::*;

    match *op {
        Inplace | Assign | AssignOp(_) => Associativity::Right,
        Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply |
        As | Colon => Associativity::Both,
    Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft |
        ShiftRight | Subtract => Associativity::Left,
        DotDot | DotDotDot => Associativity::None
    }
}

/// Convert a `hir::BinOp` to the corresponding assigning binary operator.
fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
    use rustc::hir::BinOp_::*;
    use syntax::parse::token::BinOpToken::*;

    AssocOp::AssignOp(match op.node {
        BiAdd => Plus,
        BiBitAnd => And,
        BiBitOr => Or,
        BiBitXor => Caret,
        BiDiv => Slash,
        BiMul => Star,
        BiRem => Percent,
        BiShl => Shl,
        BiShr => Shr,
        BiSub => Minus,
        BiAnd | BiEq | BiGe | BiGt | BiLe | BiLt | BiNe | BiOr => panic!("This operator does not exist"),
    })
}

/// Convert an `ast::BinOp` to the corresponding assigning binary operator.
fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
    use syntax::ast::BinOpKind::*;
    use syntax::parse::token::BinOpToken;

    AssocOp::AssignOp(match op.node {
        Add => BinOpToken::Plus,
        BitAnd => BinOpToken::And,
        BitOr => BinOpToken::Or,
        BitXor => BinOpToken::Caret,
        Div => BinOpToken::Slash,
        Mul => BinOpToken::Star,
        Rem => BinOpToken::Percent,
        Shl => BinOpToken::Shl,
        Shr => BinOpToken::Shr,
        Sub => BinOpToken::Minus,
        And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"),
    })
}
<commit_msg>Rustup to ea0dc9297283daff6486807f43e190b4eb561412 III<commit_after>use rustc::hir;
use rustc::lint::{EarlyContext, LateContext};
use std::borrow::Cow;
use std;
use syntax::ast;
use syntax::util::parser::AssocOp;
use utils::{higher, snippet};

/// A helper type to build suggestion correctly handling parenthesis.
pub enum Sugg<'a> {
    /// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
    NonParen(Cow<'a, str>),
    /// An expression that does not fit in other variants.
    MaybeParen(Cow<'a, str>),
    /// A binary operator expression, including `as`-casts and explicit type coercion.
    BinOp(AssocOp, Cow<'a, str>),
}

impl<'a> std::fmt::Display for Sugg<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => {
                s.fmt(f)
            }
        }
    }
}

impl<'a> Sugg<'a> {
    pub fn hir(cx: &LateContext, expr: &'a hir::Expr, default: &'a str) -> Sugg<'a> {
        let snippet = snippet(cx, expr.span, default);

        match expr.node {
            hir::ExprAddrOf(..) |
            hir::ExprBox(..) |
            hir::ExprClosure(..) |
            hir::ExprIf(..) |
            hir::ExprUnary(..) |
            hir::ExprMatch(..) => Sugg::MaybeParen(snippet),
            hir::ExprAgain(..) |
            hir::ExprBlock(..) |
            hir::ExprBreak(..) |
            hir::ExprCall(..) |
            hir::ExprField(..) |
            hir::ExprIndex(..) |
            hir::ExprInlineAsm(..) |
            hir::ExprLit(..) |
            hir::ExprLoop(..) |
            hir::ExprMethodCall(..) |
            hir::ExprPath(..) |
            hir::ExprRepeat(..) |
            hir::ExprRet(..) |
            hir::ExprStruct(..) |
            hir::ExprTup(..) |
            hir::ExprTupField(..) |
            hir::ExprVec(..) |
            hir::ExprWhile(..) => Sugg::NonParen(snippet),
            hir::ExprAssign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
            hir::ExprAssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
            hir::ExprBinary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
            hir::ExprCast(..) => Sugg::BinOp(AssocOp::As, snippet),
            hir::ExprType(..) => Sugg::BinOp(AssocOp::Colon, snippet),
        }
    }

    pub fn ast(cx: &EarlyContext, expr: &'a ast::Expr, default: &'a str) -> Sugg<'a> {
        use syntax::ast::RangeLimits;

        let snippet = snippet(cx, expr.span, default);

        match expr.node {
            ast::ExprKind::AddrOf(..) |
            ast::ExprKind::Box(..) |
            ast::ExprKind::Closure(..) |
            ast::ExprKind::If(..) |
            ast::ExprKind::IfLet(..) |
            ast::ExprKind::InPlace(..) |
            ast::ExprKind::Unary(..) |
            ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
            ast::ExprKind::Block(..) |
            ast::ExprKind::Break(..) |
            ast::ExprKind::Call(..) |
            ast::ExprKind::Continue(..) |
            ast::ExprKind::Field(..) |
            ast::ExprKind::ForLoop(..) |
            ast::ExprKind::Index(..) |
            ast::ExprKind::InlineAsm(..) |
            ast::ExprKind::Lit(..) |
            ast::ExprKind::Loop(..) |
            ast::ExprKind::Mac(..) |
            ast::ExprKind::MethodCall(..) |
            ast::ExprKind::Paren(..) |
            ast::ExprKind::Path(..) |
            ast::ExprKind::Repeat(..) |
            ast::ExprKind::Ret(..) |
            ast::ExprKind::Struct(..) |
            ast::ExprKind::Try(..) |
            ast::ExprKind::Tup(..) |
            ast::ExprKind::TupField(..) |
            ast::ExprKind::Vec(..) |
            ast::ExprKind::While(..) |
            ast::ExprKind::WhileLet(..) => Sugg::NonParen(snippet),
            ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
            ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotDot, snippet),
            ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
            ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
            ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
            ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
            ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
        }
    }

    /// Convenience method to create the `lhs && rhs` suggestion.
    pub fn and(&self, rhs: &Self) -> Sugg<'static> {
        make_binop(ast::BinOpKind::And, self, rhs)
    }

    /// Convenience method to create the `&<expr>` suggestion.
    pub fn addr(&self) -> Sugg<'static> {
        make_unop("&", self)
    }
}

impl<'a, 'b> std::ops::Sub<&'b Sugg<'b>> for &'a Sugg<'a> {
    type Output = Sugg<'static>;
    fn sub(self, rhs: &'b Sugg<'b>) -> Sugg<'static> {
        make_binop(ast::BinOpKind::Sub, self, rhs)
    }
}

impl<'a> std::ops::Not for &'a Sugg<'a> {
    type Output = Sugg<'static>;
    fn not(self) -> Sugg<'static> {
        make_unop("!", self)
    }
}

struct ParenHelper<T> {
    paren: bool,
    wrapped: T,
}

impl<T> ParenHelper<T> {
    fn new(paren: bool, wrapped: T) -> Self {
        ParenHelper {
            paren: paren,
            wrapped: wrapped,
        }
    }
}

impl<T: std::fmt::Display> std::fmt::Display for ParenHelper<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        if self.paren {
            write!(f, "({})", self.wrapped)
        } else {
            self.wrapped.fmt(f)
        }
    }
}

/// Build the string for `<op> <expr>` adding parenthesis when necessary.
///
/// For convenience, the operator is taken as a string because all unary operators have the same
/// precedence.
pub fn make_unop(op: &str, expr: &Sugg) -> Sugg<'static> {
    let needs_paren = !matches!(*expr, Sugg::NonParen(..));
    Sugg::MaybeParen(format!("{}{}", op, ParenHelper::new(needs_paren, expr)).into())
}

/// Build the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
///
/// Precedence of shift operator relative to other arithmetic operation is often confusing so
/// parenthesis will always be added for a mix of these.
pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
    fn is_shift(op: &AssocOp) -> bool {
        matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
    }

    fn is_arith(op: &AssocOp) -> bool {
        matches!(*op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus)
    }

    fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
        other.precedence() < op.precedence() ||
            (other.precedence() == op.precedence() &&
                ((op != other && associativity(op) != dir) ||
                 (op == other && associativity(op) != Associativity::Both))) ||
             is_shift(op) && is_arith(other) ||
             is_shift(other) && is_arith(op)
    }

    let aop = AssocOp::from_ast_binop(op);

    let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
        needs_paren(&aop, lop, Associativity::Left)
    } else {
        false
    };

    let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs {
        needs_paren(&aop, rop, Associativity::Right)
    } else {
        false
    };

    Sugg::BinOp(aop,
                format!("{} {} {}",
                        ParenHelper::new(lhs_paren, lhs),
                        op.to_string(),
                        ParenHelper::new(rhs_paren, rhs)).into())
}

#[derive(PartialEq, Eq)]
enum Associativity {
    Both,
    Left,
    None,
    Right,
}

/// Return the associativity/fixity of an operator. The difference with `AssocOp::fixity` is that
/// an operator can be both left and right associative (such as `+`:
/// `a + b + c == (a + b) + c == a + (b + c)`.
///
/// Chained `as` and explicit `:` type coercion never need inner parenthesis so they are considered
/// associative.
fn associativity(op: &AssocOp) -> Associativity {
    use syntax::util::parser::AssocOp::*;

    match *op {
        Inplace | Assign | AssignOp(_) => Associativity::Right,
        Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply |
        As | Colon => Associativity::Both,
    Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft |
        ShiftRight | Subtract => Associativity::Left,
        DotDot | DotDotDot => Associativity::None
    }
}

/// Convert a `hir::BinOp` to the corresponding assigning binary operator.
fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
    use rustc::hir::BinOp_::*;
    use syntax::parse::token::BinOpToken::*;

    AssocOp::AssignOp(match op.node {
        BiAdd => Plus,
        BiBitAnd => And,
        BiBitOr => Or,
        BiBitXor => Caret,
        BiDiv => Slash,
        BiMul => Star,
        BiRem => Percent,
        BiShl => Shl,
        BiShr => Shr,
        BiSub => Minus,
        BiAnd | BiEq | BiGe | BiGt | BiLe | BiLt | BiNe | BiOr => panic!("This operator does not exist"),
    })
}

/// Convert an `ast::BinOp` to the corresponding assigning binary operator.
fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
    use syntax::ast::BinOpKind::*;
    use syntax::parse::token::BinOpToken;

    AssocOp::AssignOp(match op.node {
        Add => BinOpToken::Plus,
        BitAnd => BinOpToken::And,
        BitOr => BinOpToken::Or,
        BitXor => BinOpToken::Caret,
        Div => BinOpToken::Slash,
        Mul => BinOpToken::Star,
        Rem => BinOpToken::Percent,
        Shl => BinOpToken::Shl,
        Shr => BinOpToken::Shr,
        Sub => BinOpToken::Minus,
        And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"),
    })
}
<|endoftext|>


<commit_before>use std::io::{ Error };
use std::result::Result;
use std::fs::File;
use std::io::LineWriter;
use std::io::Write;

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer} )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let code = format!("opcode is {:?}", opcode);
        self.target_descriptor.write_all(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let code = format!("segment is {:?}", segment);
        self.target_descriptor.write_all(&code.into_bytes());
    }
}

// Just closes the file
fn close() {

}
<commit_msg>prettify imports<commit_after>use std::io::{ Write, LineWriter, Error };
use std::result::Result;
use std::fs::File;

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer} )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let code = format!("opcode is {:?}", opcode);
        self.target_descriptor.write_all(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let code = format!("segment is {:?}", segment);
        self.target_descriptor.write_all(&code.into_bytes());
    }
}

// Just closes the file
fn close() {

}
<|endoftext|>


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

// Functions only intended to be called from code generated by the Rust Thrift
// code generator.

use crate::serialize;
use crate::ApplicationException;
use crate::ContextStack;
use crate::Deserialize;
use crate::MessageType;
use crate::Protocol;
use crate::ProtocolEncodedFinal;
use crate::ProtocolReader;
use crate::ProtocolWriter;
use crate::RequestContext;
use crate::ResultInfo;
use crate::ResultType;
use crate::Serialize;
use crate::SerializedMessage;
use anyhow::bail;
use anyhow::Result;
use futures::future::FutureExt;
use std::ffi::CStr;
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;

// Note: `variants_by_number` must be sorted by the i32 values.
pub fn enum_display(
    variants_by_number: &[(&str, i32)],
    formatter: &mut fmt::Formatter,
    number: i32,
) -> fmt::Result {
    match variants_by_number.binary_search_by_key(&number, |entry| entry.1) {
        Ok(i) => formatter.write_str(variants_by_number[i].0),
        Err(_) => write!(formatter, "{}", number),
    }
}

// Note: `variants_by_name` must be sorted by the string values.
pub fn enum_from_str(
    variants_by_name: &[(&str, i32)],
    value: &str,
    type_name: &'static str,
) -> Result<i32> {
    match variants_by_name.binary_search_by_key(&value, |entry| entry.0) {
        Ok(i) => Ok(variants_by_name[i].1),
        Err(_) => bail!("Unable to parse {} as {}", value, type_name),
    }
}

pub fn type_name_of_val<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}

/// Serialize a result as encoded into a generated *Exn type, wrapped in an envelope.
pub fn serialize_result_envelope<P, CTXT, RES>(
    name: &str,
    name_cstr: &<CTXT::ContextStack as ContextStack>::Name,
    seqid: u32,
    rctxt: &CTXT,
    ctx_stack: &mut CTXT::ContextStack,
    res: RES,
) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
    CTXT: RequestContext<Name = CStr>,
{
    let res_type = res.result_type();

    if matches!(res_type, ResultType::Error | ResultType::Exception) {
        assert_eq!(res.exn_is_declared(), res_type == ResultType::Error);

        rctxt.set_user_exception_header(res.exn_name(), &res.exn_value())?;
    }

    ctx_stack.pre_write()?;
    let envelope = serialize!(P, |p| {
        p.write_message_begin(name, res_type.message_type(), seqid);
        res.write(p);
        p.write_message_end();
    });

    ctx_stack.on_write_data(&SerializedMessage {
        protocol: P::PROTOCOL_ID,
        method_name: &name_cstr,
        buffer: PhantomData,
    })?;
    ctx_stack.post_write(0)?;

    Ok(envelope)
}

/// TODO: Currently does minimal encoding. Not sure if this'll work.
pub fn serialize_stream_item<P, RES>(res: RES) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
{
    Ok(serialize!(P, |p| {
        // TODO: We at least need to write `res_type.message_type()` here?
        res.write(p);
    }))
}

/// Serialize a request with envelope.
pub fn serialize_request_envelope<P, ARGS>(
    name: &str,
    args: &ARGS,
) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    ARGS: Serialize<P::Sizer> + Serialize<P::Serializer>,
{
    let envelope = serialize!(P, |p| {
        // Note: we send a 0 message sequence ID from clients because
        // this field should not be used by the server (except for some
        // language implementations).
        p.write_message_begin(name, MessageType::Call, 0);
        args.write(p);
        p.write_message_end();
    });

    Ok(envelope)
}

/// Deserialize a client response. This deserializes the envelope then
/// deserializes either a reply or an ApplicationException.
pub fn deserialize_response_envelope<P, T>(
    de: &mut P::Deserializer,
) -> anyhow::Result<Result<T, ApplicationException>>
where
    P: Protocol,
    T: Deserialize<P::Deserializer>,
{
    let (_, message_type, _) = de.read_message_begin(|_| ())?;

    let res = match message_type {
        MessageType::Reply => Ok(T::read(de)?),
        MessageType::Exception => Err(ApplicationException::read(de)?),
        MessageType::Call | MessageType::Oneway | MessageType::InvalidMessageType => {
            bail!("Unwanted message type `{:?}`", message_type)
        }
    };

    de.read_message_end()?;

    Ok(res)
}

/// Abstract spawning some potentially CPU-heavy work onto a CPU thread
pub trait Spawner: 'static {
    fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static;
}

/// No-op implementation of Spawner - just run on current thread
pub struct NoopSpawner;
impl Spawner for NoopSpawner {
    #[inline]
    fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        async { func() }.boxed()
    }
}

pub async fn async_deserialize_response_envelope<P, T, S>(
    de: P::Deserializer,
) -> anyhow::Result<(Result<T, ApplicationException>, P::Deserializer)>
where
    P: Protocol,
    P::Deserializer: Send,
    T: Deserialize<P::Deserializer> + Send + 'static,
    S: Spawner,
{
    S::spawn(move || {
        let mut de = de;
        let res = deserialize_response_envelope::<P, T>(&mut de);
        res.map(|res| (res, de))
    })
    .await
}
<commit_msg>Implement dummy encoder for stream payload<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Functions only intended to be called from code generated by the Rust Thrift
// code generator.

use crate::serialize;
use crate::ApplicationException;
use crate::ContextStack;
use crate::Deserialize;
use crate::MessageType;
use crate::Protocol;
use crate::ProtocolEncodedFinal;
use crate::ProtocolReader;
use crate::ProtocolWriter;
use crate::RequestContext;
use crate::ResultInfo;
use crate::ResultType;
use crate::Serialize;
use crate::SerializedMessage;
use anyhow::bail;
use anyhow::Result;
use futures::future::FutureExt;
use std::ffi::CStr;
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;

// Note: `variants_by_number` must be sorted by the i32 values.
pub fn enum_display(
    variants_by_number: &[(&str, i32)],
    formatter: &mut fmt::Formatter,
    number: i32,
) -> fmt::Result {
    match variants_by_number.binary_search_by_key(&number, |entry| entry.1) {
        Ok(i) => formatter.write_str(variants_by_number[i].0),
        Err(_) => write!(formatter, "{}", number),
    }
}

// Note: `variants_by_name` must be sorted by the string values.
pub fn enum_from_str(
    variants_by_name: &[(&str, i32)],
    value: &str,
    type_name: &'static str,
) -> Result<i32> {
    match variants_by_name.binary_search_by_key(&value, |entry| entry.0) {
        Ok(i) => Ok(variants_by_name[i].1),
        Err(_) => bail!("Unable to parse {} as {}", value, type_name),
    }
}

pub fn type_name_of_val<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}

/// Serialize a result as encoded into a generated *Exn type, wrapped in an envelope.
pub fn serialize_result_envelope<P, CTXT, RES>(
    name: &str,
    name_cstr: &<CTXT::ContextStack as ContextStack>::Name,
    seqid: u32,
    rctxt: &CTXT,
    ctx_stack: &mut CTXT::ContextStack,
    res: RES,
) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
    CTXT: RequestContext<Name = CStr>,
{
    let res_type = res.result_type();

    if matches!(res_type, ResultType::Error | ResultType::Exception) {
        assert_eq!(res.exn_is_declared(), res_type == ResultType::Error);

        rctxt.set_user_exception_header(res.exn_name(), &res.exn_value())?;
    }

    ctx_stack.pre_write()?;
    let envelope = serialize!(P, |p| {
        p.write_message_begin(name, res_type.message_type(), seqid);
        res.write(p);
        p.write_message_end();
    });

    ctx_stack.on_write_data(&SerializedMessage {
        protocol: P::PROTOCOL_ID,
        method_name: &name_cstr,
        buffer: PhantomData,
    })?;
    ctx_stack.post_write(0)?;

    Ok(envelope)
}

pub fn serialize_stream_item<P, RES>(res: RES) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
{
    Ok(serialize!(P, |p| {
        // TODO(T127840117): Handle exceptions
        // Maybe, we need to write `res_type.message_type()` here?
        res.write(p);
    }))
}

/// Serialize a request with envelope.
pub fn serialize_request_envelope<P, ARGS>(
    name: &str,
    args: &ARGS,
) -> anyhow::Result<ProtocolEncodedFinal<P>>
where
    P: Protocol,
    ARGS: Serialize<P::Sizer> + Serialize<P::Serializer>,
{
    let envelope = serialize!(P, |p| {
        // Note: we send a 0 message sequence ID from clients because
        // this field should not be used by the server (except for some
        // language implementations).
        p.write_message_begin(name, MessageType::Call, 0);
        args.write(p);
        p.write_message_end();
    });

    Ok(envelope)
}

/// Deserialize a client response. This deserializes the envelope then
/// deserializes either a reply or an ApplicationException.
pub fn deserialize_response_envelope<P, T>(
    de: &mut P::Deserializer,
) -> anyhow::Result<Result<T, ApplicationException>>
where
    P: Protocol,
    T: Deserialize<P::Deserializer>,
{
    let (_, message_type, _) = de.read_message_begin(|_| ())?;

    let res = match message_type {
        MessageType::Reply => Ok(T::read(de)?),
        MessageType::Exception => Err(ApplicationException::read(de)?),
        MessageType::Call | MessageType::Oneway | MessageType::InvalidMessageType => {
            bail!("Unwanted message type `{:?}`", message_type)
        }
    };

    de.read_message_end()?;

    Ok(res)
}

/// Abstract spawning some potentially CPU-heavy work onto a CPU thread
pub trait Spawner: 'static {
    fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static;
}

/// No-op implementation of Spawner - just run on current thread
pub struct NoopSpawner;
impl Spawner for NoopSpawner {
    #[inline]
    fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static,
    {
        async { func() }.boxed()
    }
}

pub async fn async_deserialize_response_envelope<P, T, S>(
    de: P::Deserializer,
) -> anyhow::Result<(Result<T, ApplicationException>, P::Deserializer)>
where
    P: Protocol,
    P::Deserializer: Send,
    T: Deserialize<P::Deserializer> + Send + 'static,
    S: Spawner,
{
    S::spawn(move || {
        let mut de = de;
        let res = deserialize_response_envelope::<P, T>(&mut de);
        res.map(|res| (res, de))
    })
    .await
}
<|endoftext|>


<commit_before>use std::{fs, vec, io};
use std::io::{Read, Seek, SeekFrom};

struct ForwardScanner {
    file: fs::File,
    len: u64,
    offset: usize
}

impl ForwardScanner {
    fn new(file_path: &'static str) -> io::Result<Self> {
        let file = try!(fs::File::open(file_path));
        let metadata = try!(file.metadata());
        Ok(ForwardScanner { file: file, offset: 0, len: metadata.len() })
    }

    fn read(&mut self, amount: usize) -> io::Result<vec::Vec<u8>> {
        let mut buf = vec![0u8; amount];
        let read = try!(self.file.read(buf.as_mut_slice()));
        if read < amount {
            buf.split_off(read);
        }
        self.offset = self.offset + read;
        debug!("read=> amount:{}, offset:{}", amount, self.offset);
        Ok(buf)
    }

    fn skip(&mut self, amount: i64) -> io::Result<u64> {
        let skip = try!(self.file.seek(SeekFrom::Current(amount)));
        self.offset = skip as usize;
        debug!("skip=> amount:{}, offset:{}", amount, self.offset);
        Ok(skip)
    }

    fn has_next(&mut self) -> bool {
        debug!("has_next=> len:{}, offset:{}", self.len, self.offset);
        self.len > self.offset as u64
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn forwardscanner() {
        match super::ForwardScanner::new("./resources/file1.txt") {
            Ok(mut scanner) => {
                assert_eq!(match scanner.read(10) {
                    Ok(bytes) => String::from_utf8_lossy(&bytes).into_owned(),
                    Err(_) => "".to_string()
                }, "1234567890");
                assert!(scanner.has_next());
                assert!(scanner.skip(5).is_ok());
                assert!(scanner.has_next());
                assert_eq!(match scanner.read(15) {
                    Ok(ref bytes) => String::from_utf8_lossy(bytes).into_owned(),
                    Err(_) => "".to_string()
                }, "fghij");
                assert!(!scanner.has_next());
            },
            Err(_) => assert!(false)
        }
    }
}<commit_msg>id3v2, FowardScanner -> Scanner<commit_after>use std::{fs, vec, io};
use std::io::{Read, Seek, SeekFrom};

struct Scanner {
    file: fs::File,
    len: u64,
    offset: usize
}

impl Scanner {
    fn new(file_path: &'static str) -> io::Result<Self> {
        let file = try!(fs::File::open(file_path));
        let metadata = try!(file.metadata());
        Ok(Scanner { file: file, offset: 0, len: metadata.len() })
    }

    fn read_as_bytes(&mut self, amount: usize) -> io::Result<vec::Vec<u8>> {
        let mut buf = vec![0u8; amount];
        let read = try!(self.file.read(buf.as_mut_slice()));
        if read < amount {
            buf.split_off(read);
        }
        self.offset = self.offset + read;
        debug!("read=> amount:{}, offset:{}", amount, self.offset);
        Ok(buf)
    }

    fn read_as_string(&mut self, amount: usize) -> io::Result<String> {
        let bytes = try!(self.read_as_bytes(amount));
        Ok(String::from_utf8_lossy(&bytes).into_owned())
    }

    fn _seek(&mut self, amount: i64) -> io::Result<u64> {
        let seek = try!(self.file.seek(SeekFrom::Current(amount)));
        self.offset = seek as usize;
        trace!("_seek=> amount:{}, offset:{}", amount, self.offset);
        Ok(seek)
    }

    fn skip(&mut self, amount: u64) -> io::Result<u64> {
        let skip = self._seek(amount as i64);
        debug!("skip=> amount:{}, offset:{}", amount, self.offset);
        skip
    }

    fn rewind(&mut self, amount: u64) -> io::Result<u64> {
        let rewind = self._seek(amount as i64 * -1);
        debug!("rewind=> amount:{}, offset:{}", amount, self.offset);
        rewind
    }

    fn has_next(&mut self) -> bool {
        debug!("has_next=> len:{}, offset:{}", self.len, self.offset);
        self.len > self.offset as u64
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn forwardscanner() {
        match super::Scanner::new("./resources/file1.txt") {
            Ok(mut scanner) => {
                assert_eq!(match scanner.read_as_bytes(10) {
                    Ok(bytes) => String::from_utf8_lossy(&bytes).into_owned(),
                    Err(_) => "".to_string()
                }, "1234567890");
                assert!(scanner.has_next());
                assert!(scanner.skip(5).is_ok());
                assert!(scanner.has_next());
                assert!(scanner.rewind(5).is_ok());
                assert_eq!(match scanner.read_as_bytes(15) {
                    Ok(ref bytes) => String::from_utf8_lossy(bytes).into_owned(),
                    Err(_) => "".to_string()
                }, "abcdefghij");
                assert!(!scanner.has_next());
            },
            Err(_) => assert!(false)
        }
    }
}<|endoftext|>


<commit_before>//! proc-macro server implementation
//!
//! Based on idea from <https://github.com/fedochet/rust-proc-macro-expander>
//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that
//! we could provide any TokenStream implementation.
//! The original idea from fedochet is using proc-macro2 as backend,
//! we use tt instead for better integration with RA.
//!
//! FIXME: No span and source file information is implemented yet

use super::proc_macro::{
    self,
    bridge::{self, server},
};

mod token_stream;
pub use token_stream::TokenStream;
use token_stream::TokenStreamBuilder;

mod symbol;
pub use symbol::*;

use std::{iter::FromIterator, ops::Bound};

type Group = tt::Subtree;
type TokenTree = tt::TokenTree;
type Punct = tt::Punct;
type Spacing = tt::Spacing;
type Literal = tt::Literal;
type Span = tt::TokenId;

#[derive(Clone)]
pub struct SourceFile {
    // FIXME stub
}

type Level = super::proc_macro::Level;
type LineColumn = super::proc_macro::LineColumn;

/// A structure representing a diagnostic message and associated children
/// messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    level: Level,
    message: String,
    spans: Vec<Span>,
    children: Vec<Diagnostic>,
}

impl Diagnostic {
    /// Creates a new diagnostic with the given `level` and `message`.
    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
        Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
    }
}

pub struct FreeFunctions;

#[derive(Default)]
pub struct RustAnalyzer {
    // FIXME: store span information here.
}

impl server::Types for RustAnalyzer {
    type FreeFunctions = FreeFunctions;
    type TokenStream = TokenStream;
    type SourceFile = SourceFile;
    type MultiSpan = Vec<Span>;
    type Diagnostic = Diagnostic;
    type Span = Span;
    type Symbol = Symbol;
}

impl server::FreeFunctions for RustAnalyzer {
    fn track_env_var(&mut self, _var: &str, _value: Option<&str>) {
        // FIXME: track env var accesses
        // https://github.com/rust-lang/rust/pull/71858
    }
    fn track_path(&mut self, _path: &str) {}

    fn literal_from_str(
        &mut self,
        _s: &str,
    ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
        todo!()
    }
}

impl server::TokenStream for RustAnalyzer {
    fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
        stream.is_empty()
    }
    fn from_str(&mut self, src: &str) -> Self::TokenStream {
        use std::str::FromStr;

        Self::TokenStream::from_str(src).expect("cannot parse string")
    }
    fn to_string(&mut self, stream: &Self::TokenStream) -> String {
        stream.to_string()
    }
    fn from_token_tree(
        &mut self,
        tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
    ) -> Self::TokenStream {
        match tree {
            bridge::TokenTree::Group(group) => {
                let group = Group {
                    delimiter: delim_to_internal(group.delimiter),
                    token_trees: match group.stream {
                        Some(stream) => stream.into_iter().collect(),
                        None => Vec::new(),
                    },
                };
                let tree = TokenTree::from(group);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Ident(ident) => {
                // FIXME: handle raw idents
                let text = SYMBOL_INTERNER.lock().unwrap().get(&ident.sym).clone();
                let ident: tt::Ident = tt::Ident { text, id: ident.span };
                let leaf = tt::Leaf::from(ident);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Literal(literal) => {
                let symbol = SYMBOL_INTERNER.lock().unwrap().get(&literal.symbol).clone();

                let text: tt::SmolStr = if let Some(suffix) = literal.suffix {
                    let suffix = SYMBOL_INTERNER.lock().unwrap().get(&suffix).clone();
                    format!("{symbol}{suffix}").into()
                } else {
                    symbol
                };

                let literal = tt::Literal { text, id: literal.span };
                let leaf = tt::Leaf::from(literal);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Punct(p) => {
                let punct = tt::Punct {
                    char: p.ch as char,
                    spacing: if p.joint { Spacing::Joint } else { Spacing::Alone },
                    id: p.span,
                };
                let leaf = tt::Leaf::from(punct);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }
        }
    }

    fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
        Ok(self_.clone())
    }

    fn concat_trees(
        &mut self,
        base: Option<Self::TokenStream>,
        trees: Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
    ) -> Self::TokenStream {
        let mut builder = TokenStreamBuilder::new();
        if let Some(base) = base {
            builder.push(base);
        }
        for tree in trees {
            builder.push(self.from_token_tree(tree));
        }
        builder.build()
    }

    fn concat_streams(
        &mut self,
        base: Option<Self::TokenStream>,
        streams: Vec<Self::TokenStream>,
    ) -> Self::TokenStream {
        let mut builder = TokenStreamBuilder::new();
        if let Some(base) = base {
            builder.push(base);
        }
        for stream in streams {
            builder.push(stream);
        }
        builder.build()
    }

    fn into_trees(
        &mut self,
        stream: Self::TokenStream,
    ) -> Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
        stream
            .into_iter()
            .map(|tree| match tree {
                tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
                    bridge::TokenTree::Ident(bridge::Ident {
                        sym: SYMBOL_INTERNER.lock().unwrap().intern(&ident.text),
                        // FIXME: handle raw idents
                        is_raw: false,
                        span: ident.id,
                    })
                }
                tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                    bridge::TokenTree::Literal(bridge::Literal {
                        // FIXME: handle literal kinds
                        kind: bridge::LitKind::Err,
                        symbol: SYMBOL_INTERNER.lock().unwrap().intern(&lit.text),
                        // FIXME: handle suffixes
                        suffix: None,
                        span: lit.id,
                    })
                }
                tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
                    bridge::TokenTree::Punct(bridge::Punct {
                        ch: punct.char as u8,
                        joint: punct.spacing == Spacing::Joint,
                        span: punct.id,
                    })
                }
                tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group {
                    delimiter: delim_to_external(subtree.delimiter),
                    stream: if subtree.token_trees.is_empty() {
                        None
                    } else {
                        Some(subtree.token_trees.into_iter().collect())
                    },
                    span: bridge::DelimSpan::from_single(
                        subtree.delimiter.map_or(Span::unspecified(), |del| del.id),
                    ),
                }),
            })
            .collect()
    }
}

fn delim_to_internal(d: proc_macro::Delimiter) -> Option<tt::Delimiter> {
    let kind = match d {
        proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
        proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace,
        proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket,
        proc_macro::Delimiter::None => return None,
    };
    Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
}

fn delim_to_external(d: Option<tt::Delimiter>) -> proc_macro::Delimiter {
    match d.map(|it| it.kind) {
        Some(tt::DelimiterKind::Parenthesis) => proc_macro::Delimiter::Parenthesis,
        Some(tt::DelimiterKind::Brace) => proc_macro::Delimiter::Brace,
        Some(tt::DelimiterKind::Bracket) => proc_macro::Delimiter::Bracket,
        None => proc_macro::Delimiter::None,
    }
}

fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing {
    match spacing {
        proc_macro::Spacing::Alone => Spacing::Alone,
        proc_macro::Spacing::Joint => Spacing::Joint,
    }
}

fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing {
    match spacing {
        Spacing::Alone => proc_macro::Spacing::Alone,
        Spacing::Joint => proc_macro::Spacing::Joint,
    }
}

impl server::SourceFile for RustAnalyzer {
    // FIXME these are all stubs
    fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
        true
    }
    fn path(&mut self, _file: &Self::SourceFile) -> String {
        String::new()
    }
    fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
        true
    }
}

impl server::Diagnostic for RustAnalyzer {
    fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
        let mut diag = Diagnostic::new(level, msg);
        diag.spans = spans;
        diag
    }

    fn sub(
        &mut self,
        _diag: &mut Self::Diagnostic,
        _level: Level,
        _msg: &str,
        _spans: Self::MultiSpan,
    ) {
        // FIXME handle diagnostic
        //
    }

    fn emit(&mut self, _diag: Self::Diagnostic) {
        // FIXME handle diagnostic
        // diag.emit()
    }
}

impl server::Span for RustAnalyzer {
    fn debug(&mut self, span: Self::Span) -> String {
        format!("{:?}", span.0)
    }
    fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
        SourceFile {}
    }
    fn save_span(&mut self, _span: Self::Span) -> usize {
        // FIXME stub
        0
    }
    fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
        // FIXME stub
        tt::TokenId::unspecified()
    }
    /// Recent feature, not yet in the proc_macro
    ///
    /// See PR:
    /// https://github.com/rust-lang/rust/pull/55780
    fn source_text(&mut self, _span: Self::Span) -> Option<String> {
        None
    }

    fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
        // FIXME handle span
        None
    }
    fn source(&mut self, span: Self::Span) -> Self::Span {
        // FIXME handle span
        span
    }
    fn start(&mut self, _span: Self::Span) -> LineColumn {
        // FIXME handle span
        LineColumn { line: 0, column: 0 }
    }
    fn end(&mut self, _span: Self::Span) -> LineColumn {
        // FIXME handle span
        LineColumn { line: 0, column: 0 }
    }
    fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
        // Just return the first span again, because some macros will unwrap the result.
        Some(first)
    }
    fn subspan(
        &mut self,
        span: Self::Span,
        _start: Bound<usize>,
        _end: Bound<usize>,
    ) -> Option<Self::Span> {
        // Just return the span again, because some macros will unwrap the result.
        Some(span)
    }
    fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
        // FIXME handle span
        tt::TokenId::unspecified()
    }

    fn after(&mut self, _self_: Self::Span) -> Self::Span {
        tt::TokenId::unspecified()
    }

    fn before(&mut self, _self_: Self::Span) -> Self::Span {
        tt::TokenId::unspecified()
    }
}

impl server::MultiSpan for RustAnalyzer {
    fn new(&mut self) -> Self::MultiSpan {
        // FIXME handle span
        vec![]
    }

    fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) {
        //TODP
        other.push(span)
    }
}

impl server::Symbol for RustAnalyzer {
    fn normalize_and_validate_ident(&mut self, _string: &str) -> Result<Self::Symbol, ()> {
        todo!()
    }
}

impl server::Server for RustAnalyzer {
    fn globals(&mut self) -> bridge::ExpnGlobals<Self::Span> {
        bridge::ExpnGlobals {
            def_site: Span::unspecified(),
            call_site: Span::unspecified(),
            mixed_site: Span::unspecified(),
        }
    }

    fn intern_symbol(ident: &str) -> Self::Symbol {
        SYMBOL_INTERNER.lock().unwrap().intern(&tt::SmolStr::from(ident))
    }

    fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
        f(SYMBOL_INTERNER.lock().unwrap().get(symbol).as_str())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ra_server_to_string() {
        let s = TokenStream {
            token_trees: vec![
                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                    text: "struct".into(),
                    id: tt::TokenId::unspecified(),
                })),
                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                    text: "T".into(),
                    id: tt::TokenId::unspecified(),
                })),
                tt::TokenTree::Subtree(tt::Subtree {
                    delimiter: Some(tt::Delimiter {
                        id: tt::TokenId::unspecified(),
                        kind: tt::DelimiterKind::Brace,
                    }),
                    token_trees: vec![],
                }),
            ],
        };

        assert_eq!(s.to_string(), "struct T {}");
    }

    #[test]
    fn test_ra_server_from_str() {
        use std::str::FromStr;
        let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
            delimiter: Some(tt::Delimiter {
                id: tt::TokenId::unspecified(),
                kind: tt::DelimiterKind::Parenthesis,
            }),
            token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                text: "a".into(),
                id: tt::TokenId::unspecified(),
            }))],
        });

        let t1 = TokenStream::from_str("(a)").unwrap();
        assert_eq!(t1.token_trees.len(), 1);
        assert_eq!(t1.token_trees[0], subtree_paren_a);

        let t2 = TokenStream::from_str("(a);").unwrap();
        assert_eq!(t2.token_trees.len(), 2);
        assert_eq!(t2.token_trees[0], subtree_paren_a);

        let underscore = TokenStream::from_str("_").unwrap();
        assert_eq!(
            underscore.token_trees[0],
            tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                text: "_".into(),
                id: tt::TokenId::unspecified(),
            }))
        );
    }
}
<commit_msg>implement literal_from_str (poorly)<commit_after>//! proc-macro server implementation
//!
//! Based on idea from <https://github.com/fedochet/rust-proc-macro-expander>
//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that
//! we could provide any TokenStream implementation.
//! The original idea from fedochet is using proc-macro2 as backend,
//! we use tt instead for better integration with RA.
//!
//! FIXME: No span and source file information is implemented yet

use super::proc_macro::{
    self,
    bridge::{self, server},
};

mod token_stream;
pub use token_stream::TokenStream;
use token_stream::TokenStreamBuilder;

mod symbol;
pub use symbol::*;

use std::{iter::FromIterator, ops::Bound};

type Group = tt::Subtree;
type TokenTree = tt::TokenTree;
type Punct = tt::Punct;
type Spacing = tt::Spacing;
type Literal = tt::Literal;
type Span = tt::TokenId;

#[derive(Clone)]
pub struct SourceFile {
    // FIXME stub
}

type Level = super::proc_macro::Level;
type LineColumn = super::proc_macro::LineColumn;

/// A structure representing a diagnostic message and associated children
/// messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    level: Level,
    message: String,
    spans: Vec<Span>,
    children: Vec<Diagnostic>,
}

impl Diagnostic {
    /// Creates a new diagnostic with the given `level` and `message`.
    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
        Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
    }
}

pub struct FreeFunctions;

#[derive(Default)]
pub struct RustAnalyzer {
    // FIXME: store span information here.
}

impl server::Types for RustAnalyzer {
    type FreeFunctions = FreeFunctions;
    type TokenStream = TokenStream;
    type SourceFile = SourceFile;
    type MultiSpan = Vec<Span>;
    type Diagnostic = Diagnostic;
    type Span = Span;
    type Symbol = Symbol;
}

impl server::FreeFunctions for RustAnalyzer {
    fn track_env_var(&mut self, _var: &str, _value: Option<&str>) {
        // FIXME: track env var accesses
        // https://github.com/rust-lang/rust/pull/71858
    }
    fn track_path(&mut self, _path: &str) {}

    fn literal_from_str(
        &mut self,
        s: &str,
    ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
        // TODO: keep track of LitKind and Suffix
        let symbol = SYMBOL_INTERNER.lock().unwrap().intern(s);
        Ok(bridge::Literal {
            kind: bridge::LitKind::Err,
            symbol,
            suffix: None,
            span: tt::TokenId::unspecified(),
        })
    }
}

impl server::TokenStream for RustAnalyzer {
    fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
        stream.is_empty()
    }
    fn from_str(&mut self, src: &str) -> Self::TokenStream {
        use std::str::FromStr;

        Self::TokenStream::from_str(src).expect("cannot parse string")
    }
    fn to_string(&mut self, stream: &Self::TokenStream) -> String {
        stream.to_string()
    }
    fn from_token_tree(
        &mut self,
        tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
    ) -> Self::TokenStream {
        match tree {
            bridge::TokenTree::Group(group) => {
                let group = Group {
                    delimiter: delim_to_internal(group.delimiter),
                    token_trees: match group.stream {
                        Some(stream) => stream.into_iter().collect(),
                        None => Vec::new(),
                    },
                };
                let tree = TokenTree::from(group);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Ident(ident) => {
                // FIXME: handle raw idents
                let text = SYMBOL_INTERNER.lock().unwrap().get(&ident.sym).clone();
                let ident: tt::Ident = tt::Ident { text, id: ident.span };
                let leaf = tt::Leaf::from(ident);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Literal(literal) => {
                let symbol = SYMBOL_INTERNER.lock().unwrap().get(&literal.symbol).clone();

                let text: tt::SmolStr = if let Some(suffix) = literal.suffix {
                    let suffix = SYMBOL_INTERNER.lock().unwrap().get(&suffix).clone();
                    format!("{symbol}{suffix}").into()
                } else {
                    symbol
                };

                let literal = tt::Literal { text, id: literal.span };
                let leaf = tt::Leaf::from(literal);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }

            bridge::TokenTree::Punct(p) => {
                let punct = tt::Punct {
                    char: p.ch as char,
                    spacing: if p.joint { Spacing::Joint } else { Spacing::Alone },
                    id: p.span,
                };
                let leaf = tt::Leaf::from(punct);
                let tree = TokenTree::from(leaf);
                Self::TokenStream::from_iter(vec![tree])
            }
        }
    }

    fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
        Ok(self_.clone())
    }

    fn concat_trees(
        &mut self,
        base: Option<Self::TokenStream>,
        trees: Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
    ) -> Self::TokenStream {
        let mut builder = TokenStreamBuilder::new();
        if let Some(base) = base {
            builder.push(base);
        }
        for tree in trees {
            builder.push(self.from_token_tree(tree));
        }
        builder.build()
    }

    fn concat_streams(
        &mut self,
        base: Option<Self::TokenStream>,
        streams: Vec<Self::TokenStream>,
    ) -> Self::TokenStream {
        let mut builder = TokenStreamBuilder::new();
        if let Some(base) = base {
            builder.push(base);
        }
        for stream in streams {
            builder.push(stream);
        }
        builder.build()
    }

    fn into_trees(
        &mut self,
        stream: Self::TokenStream,
    ) -> Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
        stream
            .into_iter()
            .map(|tree| match tree {
                tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
                    bridge::TokenTree::Ident(bridge::Ident {
                        sym: SYMBOL_INTERNER.lock().unwrap().intern(&ident.text),
                        // FIXME: handle raw idents
                        is_raw: false,
                        span: ident.id,
                    })
                }
                tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                    bridge::TokenTree::Literal(bridge::Literal {
                        // FIXME: handle literal kinds
                        kind: bridge::LitKind::Err,
                        symbol: SYMBOL_INTERNER.lock().unwrap().intern(&lit.text),
                        // FIXME: handle suffixes
                        suffix: None,
                        span: lit.id,
                    })
                }
                tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
                    bridge::TokenTree::Punct(bridge::Punct {
                        ch: punct.char as u8,
                        joint: punct.spacing == Spacing::Joint,
                        span: punct.id,
                    })
                }
                tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group {
                    delimiter: delim_to_external(subtree.delimiter),
                    stream: if subtree.token_trees.is_empty() {
                        None
                    } else {
                        Some(subtree.token_trees.into_iter().collect())
                    },
                    span: bridge::DelimSpan::from_single(
                        subtree.delimiter.map_or(Span::unspecified(), |del| del.id),
                    ),
                }),
            })
            .collect()
    }
}

fn delim_to_internal(d: proc_macro::Delimiter) -> Option<tt::Delimiter> {
    let kind = match d {
        proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
        proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace,
        proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket,
        proc_macro::Delimiter::None => return None,
    };
    Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
}

fn delim_to_external(d: Option<tt::Delimiter>) -> proc_macro::Delimiter {
    match d.map(|it| it.kind) {
        Some(tt::DelimiterKind::Parenthesis) => proc_macro::Delimiter::Parenthesis,
        Some(tt::DelimiterKind::Brace) => proc_macro::Delimiter::Brace,
        Some(tt::DelimiterKind::Bracket) => proc_macro::Delimiter::Bracket,
        None => proc_macro::Delimiter::None,
    }
}

fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing {
    match spacing {
        proc_macro::Spacing::Alone => Spacing::Alone,
        proc_macro::Spacing::Joint => Spacing::Joint,
    }
}

fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing {
    match spacing {
        Spacing::Alone => proc_macro::Spacing::Alone,
        Spacing::Joint => proc_macro::Spacing::Joint,
    }
}

impl server::SourceFile for RustAnalyzer {
    // FIXME these are all stubs
    fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
        true
    }
    fn path(&mut self, _file: &Self::SourceFile) -> String {
        String::new()
    }
    fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
        true
    }
}

impl server::Diagnostic for RustAnalyzer {
    fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
        let mut diag = Diagnostic::new(level, msg);
        diag.spans = spans;
        diag
    }

    fn sub(
        &mut self,
        _diag: &mut Self::Diagnostic,
        _level: Level,
        _msg: &str,
        _spans: Self::MultiSpan,
    ) {
        // FIXME handle diagnostic
        //
    }

    fn emit(&mut self, _diag: Self::Diagnostic) {
        // FIXME handle diagnostic
        // diag.emit()
    }
}

impl server::Span for RustAnalyzer {
    fn debug(&mut self, span: Self::Span) -> String {
        format!("{:?}", span.0)
    }
    fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
        SourceFile {}
    }
    fn save_span(&mut self, _span: Self::Span) -> usize {
        // FIXME stub
        0
    }
    fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span {
        // FIXME stub
        tt::TokenId::unspecified()
    }
    /// Recent feature, not yet in the proc_macro
    ///
    /// See PR:
    /// https://github.com/rust-lang/rust/pull/55780
    fn source_text(&mut self, _span: Self::Span) -> Option<String> {
        None
    }

    fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
        // FIXME handle span
        None
    }
    fn source(&mut self, span: Self::Span) -> Self::Span {
        // FIXME handle span
        span
    }
    fn start(&mut self, _span: Self::Span) -> LineColumn {
        // FIXME handle span
        LineColumn { line: 0, column: 0 }
    }
    fn end(&mut self, _span: Self::Span) -> LineColumn {
        // FIXME handle span
        LineColumn { line: 0, column: 0 }
    }
    fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
        // Just return the first span again, because some macros will unwrap the result.
        Some(first)
    }
    fn subspan(
        &mut self,
        span: Self::Span,
        _start: Bound<usize>,
        _end: Bound<usize>,
    ) -> Option<Self::Span> {
        // Just return the span again, because some macros will unwrap the result.
        Some(span)
    }
    fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span {
        // FIXME handle span
        tt::TokenId::unspecified()
    }

    fn after(&mut self, _self_: Self::Span) -> Self::Span {
        tt::TokenId::unspecified()
    }

    fn before(&mut self, _self_: Self::Span) -> Self::Span {
        tt::TokenId::unspecified()
    }
}

impl server::MultiSpan for RustAnalyzer {
    fn new(&mut self) -> Self::MultiSpan {
        // FIXME handle span
        vec![]
    }

    fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) {
        //TODP
        other.push(span)
    }
}

impl server::Symbol for RustAnalyzer {
    fn normalize_and_validate_ident(&mut self, _string: &str) -> Result<Self::Symbol, ()> {
        todo!()
    }
}

impl server::Server for RustAnalyzer {
    fn globals(&mut self) -> bridge::ExpnGlobals<Self::Span> {
        bridge::ExpnGlobals {
            def_site: Span::unspecified(),
            call_site: Span::unspecified(),
            mixed_site: Span::unspecified(),
        }
    }

    fn intern_symbol(ident: &str) -> Self::Symbol {
        SYMBOL_INTERNER.lock().unwrap().intern(&tt::SmolStr::from(ident))
    }

    fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
        f(SYMBOL_INTERNER.lock().unwrap().get(symbol).as_str())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ra_server_to_string() {
        let s = TokenStream {
            token_trees: vec![
                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                    text: "struct".into(),
                    id: tt::TokenId::unspecified(),
                })),
                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                    text: "T".into(),
                    id: tt::TokenId::unspecified(),
                })),
                tt::TokenTree::Subtree(tt::Subtree {
                    delimiter: Some(tt::Delimiter {
                        id: tt::TokenId::unspecified(),
                        kind: tt::DelimiterKind::Brace,
                    }),
                    token_trees: vec![],
                }),
            ],
        };

        assert_eq!(s.to_string(), "struct T {}");
    }

    #[test]
    fn test_ra_server_from_str() {
        use std::str::FromStr;
        let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
            delimiter: Some(tt::Delimiter {
                id: tt::TokenId::unspecified(),
                kind: tt::DelimiterKind::Parenthesis,
            }),
            token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                text: "a".into(),
                id: tt::TokenId::unspecified(),
            }))],
        });

        let t1 = TokenStream::from_str("(a)").unwrap();
        assert_eq!(t1.token_trees.len(), 1);
        assert_eq!(t1.token_trees[0], subtree_paren_a);

        let t2 = TokenStream::from_str("(a);").unwrap();
        assert_eq!(t2.token_trees.len(), 2);
        assert_eq!(t2.token_trees[0], subtree_paren_a);

        let underscore = TokenStream::from_str("_").unwrap();
        assert_eq!(
            underscore.token_trees[0],
            tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                text: "_".into(),
                id: tt::TokenId::unspecified(),
            }))
        );
    }
}
<|endoftext|>