<commit_before>//! The code in this module gathers up all of the inherent impls in
//! the current crate and organizes them in a map. It winds up
//! touching the whole crate and thus must be recomputed completely
//! for any change, but it is very cheap to compute. In practice, most
//! code in the compiler never *directly* requests this map. Instead,
//! it requests the inherent impls specific to some type (via
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.

use rustc::dep_graph::DepKind;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::{self, CrateInherentImpls, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls(
    tcx: TyCtxt<'_>,
    crate_num: CrateNum,
) -> &CrateInherentImpls {
    assert_eq!(crate_num, LOCAL_CRATE);

    let krate = tcx.hir().krate();
    let mut collect = InherentCollect {
        tcx,
        impls_map: Default::default(),
    };
    krate.visit_all_item_likes(&mut collect);
    tcx.arena.alloc(collect.impls_map)
}

/// On-demand query: yields a vector of the inherent impls for a specific type.
pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] {
    assert!(ty_def_id.is_local());

    // NB. Until we adopt the red-green dep-tracking algorithm (see
    // [the plan] for details on that), we do some hackery here to get
    // the dependencies correct.  Basically, we use a `with_ignore` to
    // read the result we want. If we didn't have the `with_ignore`,
    // we would wind up with a dependency on the entire crate, which
    // we don't want. Then we go and add dependencies on all the impls
    // in the result (which is what we wanted).
    //
    // The result is a graph with an edge from `Hir(I)` for every impl
    // `I` defined on some type `T` to `CoherentInherentImpls(T)`,
    // thus ensuring that if any of those impls change, the set of
    // inherent impls is considered dirty.
    //
    // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4

    let result = tcx.dep_graph.with_ignore(|| {
        let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
        match crate_map.inherent_impls.get(&ty_def_id) {
            Some(v) => &v[..],
            None => &[],
        }
    });

    for &impl_def_id in &result[..] {
        let def_path_hash = tcx.def_path_hash(impl_def_id);
        tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
    }

    result
}

struct InherentCollect<'tcx> {
    tcx: TyCtxt<'tcx>,
    impls_map: CrateInherentImpls,
}

impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let ty = match item.node {
            hir::ItemKind::Impl(.., None, ref ty, _) => ty,
            _ => return
        };

        let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
        let self_ty = self.tcx.type_of(def_id);
        let lang_items = self.tcx.lang_items();
        match self_ty.sty {
            ty::Adt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::Foreign(did) => {
                self.check_def_id(item, did);
            }
            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
                self.check_def_id(item, data.principal_def_id().unwrap());
            }
            ty::Char => {
                self.check_primitive_impl(def_id,
                                          lang_items.char_impl(),
                                          None,
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::Str => {
                self.check_primitive_impl(def_id,
                                          lang_items.str_impl(),
                                          lang_items.str_alloc_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_u8_impl(),
                                          lang_items.slice_u8_alloc_impl(),
                                          "slice_u8",
                                          "[u8]",
                                          item.span);
            }
            ty::Slice(_) => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_impl(),
                                          lang_items.slice_alloc_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.const_ptr_impl(),
                                          None,
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.mut_ptr_impl(),
                                          None,
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::Int(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i8_impl(),
                                          None,
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::Int(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i16_impl(),
                                          None,
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::Int(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i32_impl(),
                                          None,
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::Int(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i64_impl(),
                                          None,
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::Int(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i128_impl(),
                                          None,
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::Int(ast::IntTy::Isize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.isize_impl(),
                                          None,
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u8_impl(),
                                          None,
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u16_impl(),
                                          None,
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u32_impl(),
                                          None,
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u64_impl(),
                                          None,
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u128_impl(),
                                          None,
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::Uint(ast::UintTy::Usize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.usize_impl(),
                                          None,
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f32_impl(),
                                          lang_items.f32_runtime_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f64_impl(),
                                          lang_items.f64_runtime_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::Error => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, "impl requires a base type")
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl InherentCollect<'tcx> {
    fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
            let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
            vec.push(impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span, "impl for type defined outside of crate.")
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang_def_id2: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match (lang_def_id, lang_def_id2) {
            (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
                // OK
            }
            (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}
<commit_msg>Rollup merge of #62268 - Zoxc:inherent_impls, r=eddyb<commit_after>//! The code in this module gathers up all of the inherent impls in
//! the current crate and organizes them in a map. It winds up
//! touching the whole crate and thus must be recomputed completely
//! for any change, but it is very cheap to compute. In practice, most
//! code in the compiler never *directly* requests this map. Instead,
//! it requests the inherent impls specific to some type (via
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.

use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::{self, CrateInherentImpls, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls(
    tcx: TyCtxt<'_>,
    crate_num: CrateNum,
) -> &CrateInherentImpls {
    assert_eq!(crate_num, LOCAL_CRATE);

    let krate = tcx.hir().krate();
    let mut collect = InherentCollect {
        tcx,
        impls_map: Default::default(),
    };
    krate.visit_all_item_likes(&mut collect);
    tcx.arena.alloc(collect.impls_map)
}

/// On-demand query: yields a vector of the inherent impls for a specific type.
pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] {
    assert!(ty_def_id.is_local());

    let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
    match crate_map.inherent_impls.get(&ty_def_id) {
        Some(v) => &v[..],
        None => &[],
    }
}

struct InherentCollect<'tcx> {
    tcx: TyCtxt<'tcx>,
    impls_map: CrateInherentImpls,
}

impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let ty = match item.node {
            hir::ItemKind::Impl(.., None, ref ty, _) => ty,
            _ => return
        };

        let def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
        let self_ty = self.tcx.type_of(def_id);
        let lang_items = self.tcx.lang_items();
        match self_ty.sty {
            ty::Adt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::Foreign(did) => {
                self.check_def_id(item, did);
            }
            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
                self.check_def_id(item, data.principal_def_id().unwrap());
            }
            ty::Char => {
                self.check_primitive_impl(def_id,
                                          lang_items.char_impl(),
                                          None,
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::Str => {
                self.check_primitive_impl(def_id,
                                          lang_items.str_impl(),
                                          lang_items.str_alloc_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_u8_impl(),
                                          lang_items.slice_u8_alloc_impl(),
                                          "slice_u8",
                                          "[u8]",
                                          item.span);
            }
            ty::Slice(_) => {
                self.check_primitive_impl(def_id,
                                          lang_items.slice_impl(),
                                          lang_items.slice_alloc_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.const_ptr_impl(),
                                          None,
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          lang_items.mut_ptr_impl(),
                                          None,
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::Int(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i8_impl(),
                                          None,
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::Int(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i16_impl(),
                                          None,
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::Int(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i32_impl(),
                                          None,
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::Int(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i64_impl(),
                                          None,
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::Int(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.i128_impl(),
                                          None,
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::Int(ast::IntTy::Isize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.isize_impl(),
                                          None,
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u8_impl(),
                                          None,
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u16_impl(),
                                          None,
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u32_impl(),
                                          None,
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u64_impl(),
                                          None,
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::Uint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          lang_items.u128_impl(),
                                          None,
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::Uint(ast::UintTy::Usize) => {
                self.check_primitive_impl(def_id,
                                          lang_items.usize_impl(),
                                          None,
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f32_impl(),
                                          lang_items.f32_runtime_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::Float(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          lang_items.f64_impl(),
                                          lang_items.f64_runtime_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::Error => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, "impl requires a base type")
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl InherentCollect<'tcx> {
    fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
            let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
            vec.push(impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span, "impl for type defined outside of crate.")
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang_def_id2: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match (lang_def_id, lang_def_id2) {
            (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
                // OK
            }
            (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}
<|endoftext|>


<commit_before>//! VM implementation, traits and structs
//!
//! ### Lifecycle
//!
//! A VM can be started given a `Context` and a `BlockHeader`. The
//! user can then `fire` or `step` to run it. Those functions would
//! only fail if it needs some information (accounts in the current
//! block, or block hashes of previous blocks). If this happens, one
//! can use the function `commit_account` and `commit_blockhash` to
//! commit those information to the VM, and `fire` or `step` again
//! until it succeeds. The current VM status can always be obtained
//! using the `status` function.

mod memory;
mod stack;
mod pc;
mod storage;
mod params;
mod eval;
mod commit;
mod patch;
pub mod errors;

pub use self::memory::{Memory, SeqMemory};
pub use self::stack::Stack;
pub use self::pc::{PC, Instruction};
pub use self::storage::Storage;
pub use self::params::*;
pub use self::patch::*;
pub use self::eval::{State, Machine, MachineStatus};
pub use self::commit::{AccountCommitment, Account};

use std::collections::hash_map;
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use self::errors::{RequireError, CommitError, VMError};

/// A sequencial VM. It uses sequencial memory representation and hash
/// map storage for accounts.
pub type SeqVM = VM<SeqMemory>;

/// A VM that executes using a context and block information.
pub struct VM<M>(Vec<Machine<M>>, Vec<Context>);

#[derive(Debug, Clone)]
/// VM Status
pub enum VMStatus {
    /// A running VM.
    Running,
    /// VM is stopped with out errors.
    ExitedOk,
    /// VM is stopped due to an error. The state of the VM is before
    /// the last failing instruction.
    ExitedErr(VMError),
}

impl<M: Memory + Default> VM<M> {
    /// Create a new VM using the given context, block header and patch.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch) -> VM<M> {
        let mut machines = Vec::new();
        machines.push(Machine::new(context, block, patch, 1));
        VM(machines, Vec::new())
    }

    /// Commit an account information to this VM. This should only be
    /// used when receiving `RequireError`.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_account(commitment.clone())?;
        }
        Ok(())
    }

    /// Commit a block hash to this VM. This should only be used when
    /// receiving `RequireError`.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_blockhash(number, hash)?;
        }
        Ok(())
    }

    /// Returns the current status of the VM.
    pub fn status(&self) -> VMStatus {
        match self.0[0].status() {
            MachineStatus::Running | MachineStatus::InvokeCreate(_) | MachineStatus::InvokeCall(_, _) => VMStatus::Running,
            MachineStatus::ExitedOk => VMStatus::ExitedOk,
            MachineStatus::ExitedErr(err) => VMStatus::ExitedErr(err.into()),
        }
    }

    /// Run one instruction and return. If it succeeds, VM status can
    /// still be `Running`. If the call stack has more than one items,
    /// this will only executes the last items' one single
    /// instruction.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match self.0.last().unwrap().status().clone() {
            MachineStatus::Running => {
                self.0.last_mut().unwrap().step()
            },
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => {
                if self.0.len() <= 1 {
                    Ok(())
                } else {
                    let finished = self.0.pop().unwrap();
                    self.0.last_mut().unwrap().apply_sub(finished);
                    Ok(())
                }
            },
            MachineStatus::InvokeCall(context, _) | MachineStatus::InvokeCreate(context) => {
                self.1.push(context.clone());
                let sub = self.0.last().unwrap().derive(context);
                self.0.push(sub);
                Ok(())
            },
        }
    }

    /// Run instructions until it reaches a `RequireError` or
    /// exits. If this function succeeds, the VM status can only be
    /// either `ExitedOk` or `ExitedErr`.
    pub fn fire(&mut self) -> Result<(), RequireError> {
        loop {
            match self.status() {
                VMStatus::Running => self.step()?,
                VMStatus::ExitedOk | VMStatus::ExitedErr(_) => return Ok(()),
            }
        }
    }

    /// Returns the changed or committed accounts information up to
    /// current execution status.
    pub fn accounts(&self) -> hash_map::Values<Address, Account> {
        self.0[0].state().account_state.accounts()
    }

    /// Returns the out value, if any.
    pub fn out(&self) -> &[u8] {
        self.0[0].state().out.as_slice()
    }

    /// Returns the available gas of this VM.
    pub fn available_gas(&self) -> Gas {
        self.0[0].state().available_gas()
    }

    /// Returns the refunded gas of this VM.
    pub fn refunded_gas(&self) -> Gas {
        self.0[0].state().refunded_gas
    }

    /// Returns logs to be appended to the current block if the user
    /// decided to accept the running status of this VM.
    pub fn logs(&self) -> &[Log] {
        self.0[0].state().logs.as_slice()
    }

    /// Returns the call create history. Only used in testing.
    pub fn history(&self) -> &[Context] {
        self.1.as_slice()
    }
}
<commit_msg>Problem: missing used_gas fn in VM<commit_after>//! VM implementation, traits and structs
//!
//! ### Lifecycle
//!
//! A VM can be started given a `Context` and a `BlockHeader`. The
//! user can then `fire` or `step` to run it. Those functions would
//! only fail if it needs some information (accounts in the current
//! block, or block hashes of previous blocks). If this happens, one
//! can use the function `commit_account` and `commit_blockhash` to
//! commit those information to the VM, and `fire` or `step` again
//! until it succeeds. The current VM status can always be obtained
//! using the `status` function.

mod memory;
mod stack;
mod pc;
mod storage;
mod params;
mod eval;
mod commit;
mod patch;
pub mod errors;

pub use self::memory::{Memory, SeqMemory};
pub use self::stack::Stack;
pub use self::pc::{PC, Instruction};
pub use self::storage::Storage;
pub use self::params::*;
pub use self::patch::*;
pub use self::eval::{State, Machine, MachineStatus};
pub use self::commit::{AccountCommitment, Account};

use std::collections::hash_map;
use utils::bigint::M256;
use utils::gas::Gas;
use utils::address::Address;
use self::errors::{RequireError, CommitError, VMError};

/// A sequencial VM. It uses sequencial memory representation and hash
/// map storage for accounts.
pub type SeqVM = VM<SeqMemory>;

/// A VM that executes using a context and block information.
pub struct VM<M>(Vec<Machine<M>>, Vec<Context>);

#[derive(Debug, Clone)]
/// VM Status
pub enum VMStatus {
    /// A running VM.
    Running,
    /// VM is stopped with out errors.
    ExitedOk,
    /// VM is stopped due to an error. The state of the VM is before
    /// the last failing instruction.
    ExitedErr(VMError),
}

impl<M: Memory + Default> VM<M> {
    /// Create a new VM using the given context, block header and patch.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch) -> VM<M> {
        let mut machines = Vec::new();
        machines.push(Machine::new(context, block, patch, 1));
        VM(machines, Vec::new())
    }

    /// Commit an account information to this VM. This should only be
    /// used when receiving `RequireError`.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_account(commitment.clone())?;
        }
        Ok(())
    }

    /// Commit a block hash to this VM. This should only be used when
    /// receiving `RequireError`.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        for machine in &mut self.0 {
            machine.commit_blockhash(number, hash)?;
        }
        Ok(())
    }

    /// Returns the current status of the VM.
    pub fn status(&self) -> VMStatus {
        match self.0[0].status() {
            MachineStatus::Running | MachineStatus::InvokeCreate(_) | MachineStatus::InvokeCall(_, _) => VMStatus::Running,
            MachineStatus::ExitedOk => VMStatus::ExitedOk,
            MachineStatus::ExitedErr(err) => VMStatus::ExitedErr(err.into()),
        }
    }

    /// Run one instruction and return. If it succeeds, VM status can
    /// still be `Running`. If the call stack has more than one items,
    /// this will only executes the last items' one single
    /// instruction.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match self.0.last().unwrap().status().clone() {
            MachineStatus::Running => {
                self.0.last_mut().unwrap().step()
            },
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => {
                if self.0.len() <= 1 {
                    Ok(())
                } else {
                    let finished = self.0.pop().unwrap();
                    self.0.last_mut().unwrap().apply_sub(finished);
                    Ok(())
                }
            },
            MachineStatus::InvokeCall(context, _) | MachineStatus::InvokeCreate(context) => {
                self.1.push(context.clone());
                let sub = self.0.last().unwrap().derive(context);
                self.0.push(sub);
                Ok(())
            },
        }
    }

    /// Run instructions until it reaches a `RequireError` or
    /// exits. If this function succeeds, the VM status can only be
    /// either `ExitedOk` or `ExitedErr`.
    pub fn fire(&mut self) -> Result<(), RequireError> {
        loop {
            match self.status() {
                VMStatus::Running => self.step()?,
                VMStatus::ExitedOk | VMStatus::ExitedErr(_) => return Ok(()),
            }
        }
    }

    /// Returns the changed or committed accounts information up to
    /// current execution status.
    pub fn accounts(&self) -> hash_map::Values<Address, Account> {
        self.0[0].state().account_state.accounts()
    }

    /// Returns the out value, if any.
    pub fn out(&self) -> &[u8] {
        self.0[0].state().out.as_slice()
    }

    /// Returns the available gas of this VM.
    pub fn available_gas(&self) -> Gas {
        self.0[0].state().available_gas()
    }

    /// Returns the used gas of this VM.
    pub fn used_gas(&self) -> Gas {
        self.0[0].state().used_gas
    }

    /// Returns the refunded gas of this VM.
    pub fn refunded_gas(&self) -> Gas {
        self.0[0].state().refunded_gas
    }

    /// Returns logs to be appended to the current block if the user
    /// decided to accept the running status of this VM.
    pub fn logs(&self) -> &[Log] {
        self.0[0].state().logs.as_slice()
    }

    /// Returns the call create history. Only used in testing.
    pub fn history(&self) -> &[Context] {
        self.1.as_slice()
    }
}
<|endoftext|>


<commit_before>use crate::codec::{Decoder, Encoder};

use tokio::{net::UdpSocket, stream::Stream};

use bytes::{BufMut, BytesMut};
use futures_core::ready;
use futures_sink::Sink;
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::pin::Pin;
use std::task::{Context, Poll};

/// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using
/// the `Encoder` and `Decoder` traits to encode and decode frames.
///
/// Raw UDP sockets work with datagrams, but higher-level code usually wants to
/// batch these into meaningful chunks, called "frames". This method layers
/// framing on top of this socket by using the `Encoder` and `Decoder` traits to
/// handle encoding and decoding of messages frames. Note that the incoming and
/// outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and `Sink`;
/// grouping this into a single object is often useful for layering things which
/// require both read and write access to the underlying object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `UdpFramed` returned by this method, which will break
/// them into separate objects, allowing them to interact more easily.
#[must_use = "sinks do nothing unless polled"]
#[cfg_attr(docsrs, doc(feature = "codec-udp"))]
#[derive(Debug)]
pub struct UdpFramed<C> {
    socket: UdpSocket,
    codec: C,
    rd: BytesMut,
    wr: BytesMut,
    out_addr: SocketAddr,
    flushed: bool,
}

impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
    type Item = Result<(C::Item, SocketAddr), C::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let pin = self.get_mut();

        pin.rd.reserve(INITIAL_RD_CAPACITY);

        let (_n, addr) = unsafe {
            // Read into the buffer without having to initialize the memory.
            //
            // safety: we know tokio::net::UdpSocket never reads from the memory
            // during a recv
            let res = {
                let bytes = &mut *(pin.rd.bytes_mut() as *mut _ as *mut [u8]);
                ready!(Pin::new(&mut pin.socket).poll_recv_from(cx, bytes))
            };

            let (n, addr) = res?;
            pin.rd.advance_mut(n);
            (n, addr)
        };

        let frame_res = pin.codec.decode(&mut pin.rd);
        pin.rd.clear();
        let frame = frame_res?;
        let result = frame.map(|frame| Ok((frame, addr))); // frame -> (frame, addr)

        Poll::Ready(result)
    }
}

impl<C: Encoder + Unpin> Sink<(C::Item, SocketAddr)> for UdpFramed<C> {
    type Error = C::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        if !self.flushed {
            match self.poll_flush(cx)? {
                Poll::Ready(()) => {}
                Poll::Pending => return Poll::Pending,
            }
        }

        Poll::Ready(Ok(()))
    }

    fn start_send(self: Pin<&mut Self>, item: (C::Item, SocketAddr)) -> Result<(), Self::Error> {
        let (frame, out_addr) = item;

        let pin = self.get_mut();

        pin.codec.encode(frame, &mut pin.wr)?;
        pin.out_addr = out_addr;
        pin.flushed = false;

        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        if self.flushed {
            return Poll::Ready(Ok(()));
        }

        let Self {
            ref mut socket,
            ref mut out_addr,
            ref mut wr,
            ..
        } = *self;

        let n = ready!(socket.poll_send_to(cx, &wr, &out_addr))?;

        let wrote_all = n == self.wr.len();
        self.wr.clear();
        self.flushed = true;

        let res = if wrote_all {
            Ok(())
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "failed to write entire datagram to socket",
            )
            .into())
        };

        Poll::Ready(res)
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(self.poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }
}

const INITIAL_RD_CAPACITY: usize = 64 * 1024;
const INITIAL_WR_CAPACITY: usize = 8 * 1024;

impl<C> UdpFramed<C> {
    /// Create a new `UdpFramed` backed by the given socket and codec.
    ///
    /// See struct level documentation for more details.
    pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> {
        UdpFramed {
            socket,
            codec,
            out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
            rd: BytesMut::with_capacity(INITIAL_RD_CAPACITY),
            wr: BytesMut::with_capacity(INITIAL_WR_CAPACITY),
            flushed: true,
        }
    }

    /// Returns a reference to the underlying I/O stream wrapped by `Framed`.
    ///
    /// # Note
    ///
    /// Care should be taken to not tamper with the underlying stream of data
    /// coming in as it may corrupt the stream of frames otherwise being worked
    /// with.
    pub fn get_ref(&self) -> &UdpSocket {
        &self.socket
    }

    /// Returns a mutable reference to the underlying I/O stream wrapped by
    /// `Framed`.
    ///
    /// # Note
    ///
    /// Care should be taken to not tamper with the underlying stream of data
    /// coming in as it may corrupt the stream of frames otherwise being worked
    /// with.
    pub fn get_mut(&mut self) -> &mut UdpSocket {
        &mut self.socket
    }

    /// Consumes the `Framed`, returning its underlying I/O stream.
    pub fn into_inner(self) -> UdpSocket {
        self.socket
    }
}
<commit_msg>Fix UdpFramed doc cfg_attr (#2010)<commit_after>use crate::codec::{Decoder, Encoder};

use tokio::{net::UdpSocket, stream::Stream};

use bytes::{BufMut, BytesMut};
use futures_core::ready;
use futures_sink::Sink;
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::pin::Pin;
use std::task::{Context, Poll};

/// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using
/// the `Encoder` and `Decoder` traits to encode and decode frames.
///
/// Raw UDP sockets work with datagrams, but higher-level code usually wants to
/// batch these into meaningful chunks, called "frames". This method layers
/// framing on top of this socket by using the `Encoder` and `Decoder` traits to
/// handle encoding and decoding of messages frames. Note that the incoming and
/// outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and `Sink`;
/// grouping this into a single object is often useful for layering things which
/// require both read and write access to the underlying object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `UdpFramed` returned by this method, which will break
/// them into separate objects, allowing them to interact more easily.
#[must_use = "sinks do nothing unless polled"]
#[cfg_attr(docsrs, doc(all(feature = "codec", feature = "udp")))]
#[derive(Debug)]
pub struct UdpFramed<C> {
    socket: UdpSocket,
    codec: C,
    rd: BytesMut,
    wr: BytesMut,
    out_addr: SocketAddr,
    flushed: bool,
}

impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
    type Item = Result<(C::Item, SocketAddr), C::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let pin = self.get_mut();

        pin.rd.reserve(INITIAL_RD_CAPACITY);

        let (_n, addr) = unsafe {
            // Read into the buffer without having to initialize the memory.
            //
            // safety: we know tokio::net::UdpSocket never reads from the memory
            // during a recv
            let res = {
                let bytes = &mut *(pin.rd.bytes_mut() as *mut _ as *mut [u8]);
                ready!(Pin::new(&mut pin.socket).poll_recv_from(cx, bytes))
            };

            let (n, addr) = res?;
            pin.rd.advance_mut(n);
            (n, addr)
        };

        let frame_res = pin.codec.decode(&mut pin.rd);
        pin.rd.clear();
        let frame = frame_res?;
        let result = frame.map(|frame| Ok((frame, addr))); // frame -> (frame, addr)

        Poll::Ready(result)
    }
}

impl<C: Encoder + Unpin> Sink<(C::Item, SocketAddr)> for UdpFramed<C> {
    type Error = C::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        if !self.flushed {
            match self.poll_flush(cx)? {
                Poll::Ready(()) => {}
                Poll::Pending => return Poll::Pending,
            }
        }

        Poll::Ready(Ok(()))
    }

    fn start_send(self: Pin<&mut Self>, item: (C::Item, SocketAddr)) -> Result<(), Self::Error> {
        let (frame, out_addr) = item;

        let pin = self.get_mut();

        pin.codec.encode(frame, &mut pin.wr)?;
        pin.out_addr = out_addr;
        pin.flushed = false;

        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        if self.flushed {
            return Poll::Ready(Ok(()));
        }

        let Self {
            ref mut socket,
            ref mut out_addr,
            ref mut wr,
            ..
        } = *self;

        let n = ready!(socket.poll_send_to(cx, &wr, &out_addr))?;

        let wrote_all = n == self.wr.len();
        self.wr.clear();
        self.flushed = true;

        let res = if wrote_all {
            Ok(())
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "failed to write entire datagram to socket",
            )
            .into())
        };

        Poll::Ready(res)
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(self.poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }
}

const INITIAL_RD_CAPACITY: usize = 64 * 1024;
const INITIAL_WR_CAPACITY: usize = 8 * 1024;

impl<C> UdpFramed<C> {
    /// Create a new `UdpFramed` backed by the given socket and codec.
    ///
    /// See struct level documentation for more details.
    pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> {
        UdpFramed {
            socket,
            codec,
            out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
            rd: BytesMut::with_capacity(INITIAL_RD_CAPACITY),
            wr: BytesMut::with_capacity(INITIAL_WR_CAPACITY),
            flushed: true,
        }
    }

    /// Returns a reference to the underlying I/O stream wrapped by `Framed`.
    ///
    /// # Note
    ///
    /// Care should be taken to not tamper with the underlying stream of data
    /// coming in as it may corrupt the stream of frames otherwise being worked
    /// with.
    pub fn get_ref(&self) -> &UdpSocket {
        &self.socket
    }

    /// Returns a mutable reference to the underlying I/O stream wrapped by
    /// `Framed`.
    ///
    /// # Note
    ///
    /// Care should be taken to not tamper with the underlying stream of data
    /// coming in as it may corrupt the stream of frames otherwise being worked
    /// with.
    pub fn get_mut(&mut self) -> &mut UdpSocket {
        &mut self.socket
    }

    /// Consumes the `Framed`, returning its underlying I/O stream.
    pub fn into_inner(self) -> UdpSocket {
        self.socket
    }
}
<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
    fmt,
};

use js_int::Int;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue};

use super::Error;

/// The inner type of `CanonicalJsonValue::Object`.
pub type Object = BTreeMap<String, CanonicalJsonValue>;

#[derive(Clone, Eq, PartialEq)]
pub enum CanonicalJsonValue {
    /// Represents a JSON null value.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(null).try_into().unwrap();
    /// ```
    Null,

    /// Represents a JSON boolean.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(true).try_into().unwrap();
    /// ```
    Bool(bool),

    /// Represents a JSON integer.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(12).try_into().unwrap();
    /// ```
    Integer(Int),

    /// Represents a JSON string.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!("a string").try_into().unwrap();
    /// ```
    String(String),

    /// Represents a JSON array.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(["an", "array"]).try_into().unwrap();
    /// ```
    Array(Vec<CanonicalJsonValue>),

    /// Represents a JSON object.
    ///
    /// The map is backed by a BTreeMap to guarantee the sorting of keys.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!({ "an": "object" }).try_into().unwrap();
    /// ```
    Object(Object),
}

impl Default for CanonicalJsonValue {
    fn default() -> Self {
        Self::Null
    }
}

impl fmt::Debug for CanonicalJsonValue {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Self::Null => formatter.debug_tuple("Null").finish(),
            Self::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(),
            Self::Integer(ref v) => fmt::Debug::fmt(v, formatter),
            Self::String(ref v) => formatter.debug_tuple("String").field(v).finish(),
            Self::Array(ref v) => {
                formatter.write_str("Array(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
            Self::Object(ref v) => {
                formatter.write_str("Object(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
        }
    }
}

impl fmt::Display for CanonicalJsonValue {
    /// Display this value as a string.
    ///
    /// This `Display` implementation is intentionally unaffected by any formatting parameters,
    /// because adding extra whitespace or otherwise pretty-printing it would make it not the
    /// canonical form anymore.
    ///
    /// If you want to pretty-print a `CanonicalJsonValue` for debugging purposes, use
    /// one of `serde_json::{to_string_pretty, to_vec_pretty, to_writer_pretty}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", to_json_string(&self).map_err(|_| fmt::Error)?)
    }
}

impl TryFrom<JsonValue> for CanonicalJsonValue {
    type Error = Error;

    fn try_from(json: JsonValue) -> Result<Self, Self::Error> {
        Ok(match json {
            JsonValue::Bool(b) => Self::Bool(b),
            JsonValue::Number(num) => Self::Integer(
                Int::try_from(num.as_i64().ok_or(Error::IntConvert)?)
                    .map_err(|_| Error::IntConvert)?,
            ),
            JsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
            }
            JsonValue::String(string) => Self::String(string),
            JsonValue::Object(obj) => Self::Object(
                obj.into_iter()
                    .map(|(k, v)| Ok((k, v.try_into()?)))
                    .collect::<Result<Object, _>>()?,
            ),
            JsonValue::Null => Self::Null,
        })
    }
}

impl Serialize for CanonicalJsonValue {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Self::Null => serializer.serialize_unit(),
            Self::Bool(b) => serializer.serialize_bool(*b),
            Self::Integer(n) => n.serialize(serializer),
            Self::String(s) => serializer.serialize_str(s),
            Self::Array(v) => v.serialize(serializer),
            Self::Object(m) => {
                use serde::ser::SerializeMap;
                let mut map = serializer.serialize_map(Some(m.len()))?;
                for (k, v) in m {
                    map.serialize_entry(k, v)?;
                }
                map.end()
            }
        }
    }
}

impl<'de> Deserialize<'de> for CanonicalJsonValue {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<CanonicalJsonValue, D::Error>
    where
        D: Deserializer<'de>,
    {
        let val = JsonValue::deserialize(deserializer)?;
        Ok(val.try_into().map_err(serde::de::Error::custom)?)
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::json;

    use super::CanonicalJsonValue;

    #[test]
    fn to_string() {
        const CANONICAL_STR: &str = r#"{"city":"London","street":"10 Downing Street"}"#;

        let json: CanonicalJsonValue =
            json!({ "city": "London", "street": "10 Downing Street" }).try_into().unwrap();

        assert_eq!(format!("{}", json), CANONICAL_STR);
        assert_eq!(format!("{:#}", json), CANONICAL_STR);
    }
}
<commit_msg>Remove useless questionmark + Ok<commit_after>use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
    fmt,
};

use js_int::Int;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue};

use super::Error;

/// The inner type of `CanonicalJsonValue::Object`.
pub type Object = BTreeMap<String, CanonicalJsonValue>;

#[derive(Clone, Eq, PartialEq)]
pub enum CanonicalJsonValue {
    /// Represents a JSON null value.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(null).try_into().unwrap();
    /// ```
    Null,

    /// Represents a JSON boolean.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(true).try_into().unwrap();
    /// ```
    Bool(bool),

    /// Represents a JSON integer.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(12).try_into().unwrap();
    /// ```
    Integer(Int),

    /// Represents a JSON string.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!("a string").try_into().unwrap();
    /// ```
    String(String),

    /// Represents a JSON array.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(["an", "array"]).try_into().unwrap();
    /// ```
    Array(Vec<CanonicalJsonValue>),

    /// Represents a JSON object.
    ///
    /// The map is backed by a BTreeMap to guarantee the sorting of keys.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!({ "an": "object" }).try_into().unwrap();
    /// ```
    Object(Object),
}

impl Default for CanonicalJsonValue {
    fn default() -> Self {
        Self::Null
    }
}

impl fmt::Debug for CanonicalJsonValue {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Self::Null => formatter.debug_tuple("Null").finish(),
            Self::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(),
            Self::Integer(ref v) => fmt::Debug::fmt(v, formatter),
            Self::String(ref v) => formatter.debug_tuple("String").field(v).finish(),
            Self::Array(ref v) => {
                formatter.write_str("Array(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
            Self::Object(ref v) => {
                formatter.write_str("Object(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
        }
    }
}

impl fmt::Display for CanonicalJsonValue {
    /// Display this value as a string.
    ///
    /// This `Display` implementation is intentionally unaffected by any formatting parameters,
    /// because adding extra whitespace or otherwise pretty-printing it would make it not the
    /// canonical form anymore.
    ///
    /// If you want to pretty-print a `CanonicalJsonValue` for debugging purposes, use
    /// one of `serde_json::{to_string_pretty, to_vec_pretty, to_writer_pretty}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", to_json_string(&self).map_err(|_| fmt::Error)?)
    }
}

impl TryFrom<JsonValue> for CanonicalJsonValue {
    type Error = Error;

    fn try_from(json: JsonValue) -> Result<Self, Self::Error> {
        Ok(match json {
            JsonValue::Bool(b) => Self::Bool(b),
            JsonValue::Number(num) => Self::Integer(
                Int::try_from(num.as_i64().ok_or(Error::IntConvert)?)
                    .map_err(|_| Error::IntConvert)?,
            ),
            JsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
            }
            JsonValue::String(string) => Self::String(string),
            JsonValue::Object(obj) => Self::Object(
                obj.into_iter()
                    .map(|(k, v)| Ok((k, v.try_into()?)))
                    .collect::<Result<Object, _>>()?,
            ),
            JsonValue::Null => Self::Null,
        })
    }
}

impl Serialize for CanonicalJsonValue {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Self::Null => serializer.serialize_unit(),
            Self::Bool(b) => serializer.serialize_bool(*b),
            Self::Integer(n) => n.serialize(serializer),
            Self::String(s) => serializer.serialize_str(s),
            Self::Array(v) => v.serialize(serializer),
            Self::Object(m) => {
                use serde::ser::SerializeMap;
                let mut map = serializer.serialize_map(Some(m.len()))?;
                for (k, v) in m {
                    map.serialize_entry(k, v)?;
                }
                map.end()
            }
        }
    }
}

impl<'de> Deserialize<'de> for CanonicalJsonValue {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<CanonicalJsonValue, D::Error>
    where
        D: Deserializer<'de>,
    {
        let val = JsonValue::deserialize(deserializer)?;
        val.try_into().map_err(serde::de::Error::custom)
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::json;

    use super::CanonicalJsonValue;

    #[test]
    fn to_string() {
        const CANONICAL_STR: &str = r#"{"city":"London","street":"10 Downing Street"}"#;

        let json: CanonicalJsonValue =
            json!({ "city": "London", "street": "10 Downing Street" }).try_into().unwrap();

        assert_eq!(format!("{}", json), CANONICAL_STR);
        assert_eq!(format!("{:#}", json), CANONICAL_STR);
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
pub mod tests {
    use crate::arch::cpu::Cpu;
    use crate::arch::memory::Memory;
    use crate::arch::rom_structs::{Bank, Header, NesRom};

    pub fn setup_tests() -> Cpu {
        let rom = NesRom::new(
            Header::from_bytes(&[0; 16]),
            vec![
                Bank {
                    ram: false,
                    enabled: true,
                    writable: false,
                    battery: false,
                    id: "bank0".to_string(),
                    data: vec![0; 0x8000],
                }
            ],
            1,
        );
        let mem = Memory::new(rom);
        let mut cpu = Cpu::new(mem);

        cpu.registers.pc = 0x100;

        cpu
    }
}
<commit_msg>fixed tests<commit_after>#[cfg(test)]
pub mod tests {
    use crate::arch::cpu::Cpu;
    use crate::arch::memory::Memory;
    use crate::arch::rom_structs::{Bank, INesHeader, NesRom};

    pub fn setup_tests() -> Cpu {
        let rom = NesRom::new(
            INesHeader::from_bytes(&[0; 16]),
            vec![
                Bank {
                    ram: false,
                    enabled: true,
                    writable: false,
                    battery: false,
                    id: "bank0".to_string(),
                    data: vec![0; 0x8000],
                }
            ],
            1,
        );
        let mem = Memory::new(rom);
        let mut cpu = Cpu::new(mem);

        cpu.registers.pc = 0x100;

        cpu
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Networking primitives for TCP/UDP communication
//!
//! > **NOTE**: This module is very much a work in progress and is under active
//! > development.

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use sys_common::net2 as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub use self::parser::AddrParseError;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    #[stable(feature = "rust1", since = "1.0.0")]
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    #[stable(feature = "rust1", since = "1.0.0")]
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    #[stable(feature = "rust1", since = "1.0.0")]
    Both,
}

#[doc(hidden)]
trait NetInt {
    fn from_be(i: Self) -> Self;
    fn to_be(&self) -> Self;
}
macro_rules! doit {
    ($($t:ident)*) => ($(impl NetInt for $t {
        fn from_be(i: Self) -> Self { <$t>::from_be(i) }
        fn to_be(&self) -> Self { <$t>::to_be(*self) }
    })*)
}
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

fn hton<I: NetInt>(i: I) -> I { i.to_be() }
fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses")
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub struct LookupHost(net_imp::LookupHost);

#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// # #![feature(lookup_host)]
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}

/// Resolve the given address to a hostname.
///
/// This function may perform a DNS query to resolve `addr` and may also inspect
/// system configuration to resolve the specified address. If the address
/// cannot be resolved, it is returned in string format.
#[unstable(feature = "lookup_addr", reason = "recent addition")]
pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
    net_imp::lookup_addr(addr)
}
<commit_msg>remove stability note from std::net<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Networking primitives for TCP/UDP communication.

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use sys_common::net2 as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub use self::parser::AddrParseError;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    #[stable(feature = "rust1", since = "1.0.0")]
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    #[stable(feature = "rust1", since = "1.0.0")]
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    #[stable(feature = "rust1", since = "1.0.0")]
    Both,
}

#[doc(hidden)]
trait NetInt {
    fn from_be(i: Self) -> Self;
    fn to_be(&self) -> Self;
}
macro_rules! doit {
    ($($t:ident)*) => ($(impl NetInt for $t {
        fn from_be(i: Self) -> Self { <$t>::from_be(i) }
        fn to_be(&self) -> Self { <$t>::to_be(*self) }
    })*)
}
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

fn hton<I: NetInt>(i: I) -> I { i.to_be() }
fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses")
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub struct LookupHost(net_imp::LookupHost);

#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// # #![feature(lookup_host)]
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}

/// Resolve the given address to a hostname.
///
/// This function may perform a DNS query to resolve `addr` and may also inspect
/// system configuration to resolve the specified address. If the address
/// cannot be resolved, it is returned in string format.
#[unstable(feature = "lookup_addr", reason = "recent addition")]
pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
    net_imp::lookup_addr(addr)
}
<|endoftext|>


<commit_before>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{self, JoinHandle};

use crate::{constants::*, refiner};
use regex::Regex;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> = vec![
        ("diff ", BOLD),
        ("index ", BOLD),
        ("--- ", BOLD),
        ("+++ ", BOLD),
        ("@@ ", HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return static_header_prefix.1;
        }
    }

    return "";
}

fn print<W: io::Write + Send>(stream: &mut BufWriter<W>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

pub struct LineCollector {
    old_text: String,
    new_text: String,
    plain_text: String,
    consumer_thread: Option<JoinHandle<()>>,
    queue_putter: Sender<String>,
}

impl Drop for LineCollector {
    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();

        // Tell the consumer thread to drain and quit. Sending an empty string
        // like this is the secret handshake for requesting a shutdown.
        self.queue_putter.send("".to_string()).unwrap();

        // Wait for the consumer thread to finish
        // https://stackoverflow.com/q/57670145/473672
        self.consumer_thread.take().map(JoinHandle::join);

        // FIXME: Do we need to shut down our executor as well?
    }
}

impl LineCollector {
    pub fn new<W: io::Write + Send + 'static>(output: W) -> LineCollector {
        // FIXME: Start an executor here with one thread per logical CPU core

        // Allocate a queue where we can push our futures to the consumer thread
        //
        // FIXME: Once we get another thread consuming this, this queue should
        // be bounded to 2x the number of logical CPUs. 1x for the entries that
        // need CPU time for diffing, and another 1x that just contain text to
        // print and won't need any processing time.
        let (queue_putter, queue_getter): (Sender<String>, Receiver<String>) = channel();

        // This thread takes futures and prints their results
        let consumer = thread::spawn(move || {
            let mut output = BufWriter::new(output);

            loop {
                if let Ok(print_me) = queue_getter.recv() {
                    if print_me.is_empty() {
                        // Secret handshake received, done!
                        break;
                    }
                    print(&mut output, &print_me);
                }
            }
        });

        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            consumer_thread: Some(consumer),
            queue_putter,
        };
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        // FIXME: This should be enqueued as a future containing the refiner::format() call
        let mut output = String::new();
        for line in refiner::format(&self.old_text, &self.new_text) {
            output.push_str(&line);
            output.push('\n');
        }
        self.queue_putter.send(output).unwrap();

        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        // FIXME: Create an already-resolved future returning this text, then
        // store that future in our queue.
        self.queue_putter
            .send(String::from(&self.plain_text))
            .unwrap();

        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..]);
        self.old_text.push('\n');
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..]);
        self.new_text.push('\n');
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            self.consume_plain_line(&format!("{}{}{}", fixed_highlight, line, NORMAL));
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<commit_msg>Bound the queue<commit_after>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::thread::{self, JoinHandle};

use crate::{constants::*, refiner};
use regex::Regex;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> = vec![
        ("diff ", BOLD),
        ("index ", BOLD),
        ("--- ", BOLD),
        ("+++ ", BOLD),
        ("@@ ", HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return static_header_prefix.1;
        }
    }

    return "";
}

fn print<W: io::Write + Send>(stream: &mut BufWriter<W>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

pub struct LineCollector {
    old_text: String,
    new_text: String,
    plain_text: String,
    consumer_thread: Option<JoinHandle<()>>,
    queue_putter: SyncSender<String>,
}

impl Drop for LineCollector {
    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();

        // Tell the consumer thread to drain and quit. Sending an empty string
        // like this is the secret handshake for requesting a shutdown.
        self.queue_putter.send("".to_string()).unwrap();

        // Wait for the consumer thread to finish
        // https://stackoverflow.com/q/57670145/473672
        self.consumer_thread.take().map(JoinHandle::join);
    }
}

impl LineCollector {
    pub fn new<W: io::Write + Send + 'static>(output: W) -> LineCollector {
        // Allocate a queue where we can push our futures to the consumer thread
        //
        // FIXME: The queue should be bounded to 2x the number of logical CPUs.
        // 1x for the entries that need CPU time for diffing, and another 1x
        // that just contain text to print and won't need any processing time.
        let (queue_putter, queue_getter): (SyncSender<String>, Receiver<String>) = sync_channel(16);

        // This thread takes futures and prints their results
        let consumer = thread::spawn(move || {
            let mut output = BufWriter::new(output);

            loop {
                if let Ok(print_me) = queue_getter.recv() {
                    if print_me.is_empty() {
                        // Secret handshake received, done!
                        break;
                    }
                    print(&mut output, &print_me);
                }
            }
        });

        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            consumer_thread: Some(consumer),
            queue_putter,
        };
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        // FIXME: This should be enqueued as a future containing the refiner::format() call
        let mut output = String::new();
        for line in refiner::format(&self.old_text, &self.new_text) {
            output.push_str(&line);
            output.push('\n');
        }
        self.queue_putter.send(output).unwrap();

        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        // FIXME: Create an already-resolved future returning this text, then
        // store that future in our queue.
        self.queue_putter
            .send(String::from(&self.plain_text))
            .unwrap();

        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..]);
        self.old_text.push('\n');
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..]);
        self.new_text.push('\n');
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            self.consume_plain_line(&format!("{}{}{}", fixed_highlight, line, NORMAL));
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<|endoftext|>