<commit_before>use actix::prelude::*;
use godcoin::prelude::*;
use log::{info, warn};
use std::{mem, sync::Arc, time::Duration};

#[derive(Message)]
pub struct StartProductionLoop;

#[derive(Message)]
pub struct ForceProduceBlock;

#[derive(Message)]
#[rtype(result = "Result<(), TxValidateError>")]
pub struct PushTx(pub TxVariant);

#[derive(MessageResponse)]
pub struct TxValidateError(pub verify::TxErr);

pub struct Minter {
    chain: Arc<Blockchain>,
    minter_key: KeyPair,
    wallet_addr: ScriptHash,
    txs: Vec<TxVariant>,
}

impl Actor for Minter {
    type Context = Context<Self>;
}

impl Minter {
    pub fn new(chain: Arc<Blockchain>, minter_key: KeyPair, wallet_addr: ScriptHash) -> Self {
        Self {
            chain,
            minter_key,
            wallet_addr,
            txs: Vec::with_capacity(1024),
        }
    }

    fn produce(&mut self) {
        let mut transactions = Vec::with_capacity(1024);
        mem::swap(&mut transactions, &mut self.txs);

        let timestamp = util::get_epoch_ms();

        transactions.push(TxVariant::RewardTx(RewardTx {
            base: Tx {
                tx_type: TxType::REWARD,
                fee: "0 GRAEL".parse().unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            to: self.wallet_addr.clone(),
            rewards: Asset::default(),
        }));

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block).unwrap();
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
    }
}

impl Handler<StartProductionLoop> for Minter {
    type Result = ();

    fn handle(&mut self, _: StartProductionLoop, ctx: &mut Self::Context) -> Self::Result {
        let dur = Duration::from_secs(3);
        ctx.run_interval(dur, |minter, _| {
            minter.produce();
        });
    }
}

impl Handler<ForceProduceBlock> for Minter {
    type Result = ();

    fn handle(&mut self, _: ForceProduceBlock, _: &mut Self::Context) -> Self::Result {
        warn!("Forcing produced block...");
        self.produce();
    }
}

impl Handler<PushTx> for Minter {
    type Result = Result<(), TxValidateError>;

    fn handle(&mut self, msg: PushTx, _: &mut Self::Context) -> Self::Result {
        static CONFIG: verify::Config = verify::Config::strict();
        let tx = msg.0;
        self.chain
            .verify_tx(&tx, &self.txs, CONFIG)
            .map_err(TxValidateError)?;
        self.txs.push(tx);
        Ok(())
    }
}
<commit_msg>Use run_later instead of interval to ensure debugging doesn't mass produce blocks<commit_after>use actix::prelude::*;
use godcoin::prelude::*;
use log::{info, warn};
use std::{mem, sync::Arc, time::Duration};

#[derive(Message)]
pub struct StartProductionLoop;

#[derive(Message)]
pub struct ForceProduceBlock;

#[derive(Message)]
#[rtype(result = "Result<(), TxValidateError>")]
pub struct PushTx(pub TxVariant);

#[derive(MessageResponse)]
pub struct TxValidateError(pub verify::TxErr);

pub struct Minter {
    chain: Arc<Blockchain>,
    minter_key: KeyPair,
    wallet_addr: ScriptHash,
    txs: Vec<TxVariant>,
}

impl Actor for Minter {
    type Context = Context<Self>;
}

impl Minter {
    pub fn new(chain: Arc<Blockchain>, minter_key: KeyPair, wallet_addr: ScriptHash) -> Self {
        Self {
            chain,
            minter_key,
            wallet_addr,
            txs: Vec::with_capacity(1024),
        }
    }

    fn produce(&mut self) {
        let mut transactions = Vec::with_capacity(1024);
        mem::swap(&mut transactions, &mut self.txs);

        let timestamp = util::get_epoch_ms();

        transactions.push(TxVariant::RewardTx(RewardTx {
            base: Tx {
                tx_type: TxType::REWARD,
                fee: "0 GRAEL".parse().unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            to: self.wallet_addr.clone(),
            rewards: Asset::default(),
        }));

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block).unwrap();
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
    }
}

impl Handler<StartProductionLoop> for Minter {
    type Result = ();

    fn handle(&mut self, _: StartProductionLoop, ctx: &mut Self::Context) -> Self::Result {
        let dur = Duration::from_secs(3);
        ctx.run_later(dur, |minter, ctx| {
            minter.produce();
            ctx.notify(StartProductionLoop);
        });
    }
}

impl Handler<ForceProduceBlock> for Minter {
    type Result = ();

    fn handle(&mut self, _: ForceProduceBlock, _: &mut Self::Context) -> Self::Result {
        warn!("Forcing produced block...");
        self.produce();
    }
}

impl Handler<PushTx> for Minter {
    type Result = Result<(), TxValidateError>;

    fn handle(&mut self, msg: PushTx, _: &mut Self::Context) -> Self::Result {
        static CONFIG: verify::Config = verify::Config::strict();
        let tx = msg.0;
        self.chain
            .verify_tx(&tx, &self.txs, CONFIG)
            .map_err(TxValidateError)?;
        self.txs.push(tx);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::Underscore;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;

use crate::check::{
    method::probe::{self, Pick},
    FnCtxt,
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub(super) fn lint_dot_call_from_2018(
        &self,
        self_ty: Ty<'tcx>,
        segment: &hir::PathSegment<'_>,
        span: Span,
        call_expr: &'tcx hir::Expr<'tcx>,
        self_expr: &'tcx hir::Expr<'tcx>,
        pick: &Pick<'tcx>,
        args: &'tcx [hir::Expr<'tcx>],
    ) {
        debug!(
            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
            segment.ident, self_ty, call_expr, self_expr
        );

        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        // `try_into` was added to the prelude in Rust 2021.
        // `into_iter` wasn't, but `[T; N].into_iter()` doesn't resolve to
        // IntoIterator::into_iter before Rust 2021, which results in the same
        // problem.
        if !matches!(segment.ident.name, sym::try_into | sym::into_iter) {
            return;
        }

        let prelude_or_array_lint = if segment.ident.name == sym::into_iter {
            // The `into_iter` problem is only a thing for arrays.
            if let Array(..) = self_ty.kind() {
                // In this case, it wasn't really a prelude addition that was the problem.
                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
                rustc_lint::ARRAY_INTO_ITER
            } else {
                // No problem in this case.
                return;
            }
        } else {
            RUST_2021_PRELUDE_COLLISIONS
        };

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
            // avoid repeatedly adding unneeded `&*`s
            if pick.autoderefs == 1
                && matches!(
                    pick.autoref_or_ptr_adjustment,
                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
                )
                && matches!(self_ty.kind(), Ref(..))
            {
                return;
            }

            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
                return;
            }

            // Inherent impls only require not relying on autoref and autoderef in order to
            // ensure that the trait implementation won't be used
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                self_expr.hir_id,
                self_expr.span,
                |lint| {
                    let sp = self_expr.span;

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let derefs = "*".repeat(pick.autoderefs);

                    let autoref = match pick.autoref_or_ptr_adjustment {
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Mut,
                            ..
                        }) => "&mut ",
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Not,
                            ..
                        }) => "&",
                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                    };
                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                    {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}{} as *const _", derefs, self_expr)
                        } else {
                            format!("{}{}{}", autoref, derefs, self_expr)
                        };

                        lint.span_suggestion(
                            sp,
                            "disambiguate the method call",
                            format!("({})", self_adjusted),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}(...) as *const _", derefs)
                        } else {
                            format!("{}{}...", autoref, derefs)
                        };
                        lint.span_help(
                            sp,
                            &format!("disambiguate the method call with `({})`", self_adjusted,),
                        );
                    }

                    lint.emit();
                },
            );
        } else {
            // trait implementations require full disambiguation to not clash with the new prelude
            // additions (i.e. convert from dot-call to fully-qualified call)
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                call_expr.hir_id,
                call_expr.span,
                |lint| {
                    let sp = call_expr.span;
                    let trait_name = self.trait_path_or_bare_name(
                        span,
                        call_expr.hir_id,
                        pick.item.container.id(),
                    );

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
                    if precise {
                        let args = args
                            .iter()
                            .skip(1)
                            .map(|arg| {
                                format!(
                                    ", {}",
                                    self.sess().source_map().span_to_snippet(arg.span).unwrap()
                                )
                            })
                            .collect::<String>();

                        lint.span_suggestion(
                            sp,
                            "disambiguate the associated function",
                            format!(
                                "{}::{}({}{})",
                                trait_name, segment.ident.name, self_adjusted, args
                            ),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        lint.span_help(
                            sp,
                            &format!(
                                "disambiguate the associated function with `{}::{}(...)`",
                                trait_name, segment.ident,
                            ),
                        );
                    }

                    lint.emit();
                },
            );
        }
    }

    pub(super) fn lint_fully_qualified_call_from_2018(
        &self,
        span: Span,
        method_name: Ident,
        self_ty: Ty<'tcx>,
        self_ty_span: Span,
        expr_id: hir::HirId,
        pick: &Pick<'tcx>,
    ) {
        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        // These are the fully qualified methods added to prelude in Rust 2021
        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
            return;
        }

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        // For from_iter, check if the type actually implements FromIterator.
        // If we know it does not, we don't need to warn.
        if method_name.name == sym::from_iter {
            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
                if !self
                    .infcx
                    .type_implements_trait(
                        trait_def_id,
                        self_ty,
                        InternalSubsts::empty(),
                        self.param_env,
                    )
                    .may_apply()
                {
                    return;
                }
            }
        }

        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
        // since such methods take precedence over trait methods.
        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
            return;
        }

        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
            // "type" refers to either a type or, more likely, a trait from which
            // the associated function or method is from.
            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
            let trait_generics = self.tcx.generics_of(pick.item.container.id());

            let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
            let trait_name = if parameter_count == 0 {
                trait_path
            } else {
                format!(
                    "{}<{}>",
                    trait_path,
                    std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
                )
            };

            let mut lint = lint.build(&format!(
                "trait-associated function `{}` will become ambiguous in Rust 2021",
                method_name.name
            ));

            let self_ty_name = self
                .sess()
                .source_map()
                .span_to_snippet(self_ty_span)
                .unwrap_or_else(|_| self_ty.to_string());

            let self_ty_generics_count = match self_ty.kind() {
                // Get the number of generics the self type has (if an Adt) unless we can determine that
                // the user has written the self type with generics already which we (naively) do by looking
                // for a "<" in `self_ty_name`.
                Adt(def, _) if !self_ty_name.contains('<') => self.tcx.generics_of(def.did).count(),
                _ => 0,
            };
            let self_ty_generics = if self_ty_generics_count > 0 {
                format!("<{}>", vec!["_"; self_ty_generics_count].join(", "))
            } else {
                String::new()
            };
            lint.span_suggestion(
                span,
                "disambiguate the associated function",
                format!(
                    "<{}{} as {}>::{}",
                    self_ty_name, self_ty_generics, trait_name, method_name.name,
                ),
                Applicability::MachineApplicable,
            );

            lint.emit();
        });
    }

    fn trait_path_or_bare_name(
        &self,
        span: Span,
        expr_hir_id: HirId,
        trait_def_id: DefId,
    ) -> String {
        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
            let key = self.tcx.def_key(trait_def_id);
            format!("{}", key.disambiguated_data.data)
        })
    }

    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
        if applicable_trait.import_ids.is_empty() {
            // The trait was declared within the module, we only need to use its name.
            return None;
        }

        let import_items: Vec<_> = applicable_trait
            .import_ids
            .iter()
            .map(|&import_id| {
                let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
                self.tcx.hir().expect_item(hir_id)
            })
            .collect();

        // Find an identifier with which this trait was imported (note that `_` doesn't count).
        let any_id = import_items
            .iter()
            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
            .next();
        if let Some(any_id) = any_id {
            return Some(format!("{}", any_id));
        }

        // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
        // so just take the first one.
        match import_items[0].kind {
            ItemKind::Use(path, _) => Some(
                path.segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join("::"),
            ),
            _ => {
                span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
            }
        }
    }

    /// Creates a string version of the `expr` that includes explicit adjustments.
    /// Returns the string and also a bool indicating whther this is a *precise*
    /// suggestion.
    fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
        let derefs = "*".repeat(pick.autoderefs);

        let autoref = match pick.autoref_or_ptr_adjustment {
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
        };

        let (expr_text, precise) =
            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
                (expr_text, true)
            } else {
                ("(..)".to_string(), false)
            };

        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
            pick.autoref_or_ptr_adjustment
        {
            format!("{}{} as *const _", derefs, expr_text)
        } else {
            format!("{}{}{}", autoref, derefs, expr_text)
        };

        (adjusted_text, precise)
    }
}
<commit_msg>Turn to ifs into a match.<commit_after>use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::Underscore;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;

use crate::check::{
    method::probe::{self, Pick},
    FnCtxt,
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub(super) fn lint_dot_call_from_2018(
        &self,
        self_ty: Ty<'tcx>,
        segment: &hir::PathSegment<'_>,
        span: Span,
        call_expr: &'tcx hir::Expr<'tcx>,
        self_expr: &'tcx hir::Expr<'tcx>,
        pick: &Pick<'tcx>,
        args: &'tcx [hir::Expr<'tcx>],
    ) {
        debug!(
            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
            segment.ident, self_ty, call_expr, self_expr
        );

        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        let prelude_or_array_lint = match segment.ident.name {
            // `try_into` was added to the prelude in Rust 2021.
            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
            // `into_iter` wasn't added to the prelude,
            // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
            // before Rust 2021, which results in the same problem.
            // It is only a problem for arrays.
            sym::into_iter if let Array(..) = self_ty.kind() => {
                // In this case, it wasn't really a prelude addition that was the problem.
                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
                rustc_lint::ARRAY_INTO_ITER
            }
            _ => return,
        };

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
            // avoid repeatedly adding unneeded `&*`s
            if pick.autoderefs == 1
                && matches!(
                    pick.autoref_or_ptr_adjustment,
                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
                )
                && matches!(self_ty.kind(), Ref(..))
            {
                return;
            }

            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
                return;
            }

            // Inherent impls only require not relying on autoref and autoderef in order to
            // ensure that the trait implementation won't be used
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                self_expr.hir_id,
                self_expr.span,
                |lint| {
                    let sp = self_expr.span;

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let derefs = "*".repeat(pick.autoderefs);

                    let autoref = match pick.autoref_or_ptr_adjustment {
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Mut,
                            ..
                        }) => "&mut ",
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Not,
                            ..
                        }) => "&",
                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                    };
                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                    {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}{} as *const _", derefs, self_expr)
                        } else {
                            format!("{}{}{}", autoref, derefs, self_expr)
                        };

                        lint.span_suggestion(
                            sp,
                            "disambiguate the method call",
                            format!("({})", self_adjusted),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}(...) as *const _", derefs)
                        } else {
                            format!("{}{}...", autoref, derefs)
                        };
                        lint.span_help(
                            sp,
                            &format!("disambiguate the method call with `({})`", self_adjusted,),
                        );
                    }

                    lint.emit();
                },
            );
        } else {
            // trait implementations require full disambiguation to not clash with the new prelude
            // additions (i.e. convert from dot-call to fully-qualified call)
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                call_expr.hir_id,
                call_expr.span,
                |lint| {
                    let sp = call_expr.span;
                    let trait_name = self.trait_path_or_bare_name(
                        span,
                        call_expr.hir_id,
                        pick.item.container.id(),
                    );

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
                    if precise {
                        let args = args
                            .iter()
                            .skip(1)
                            .map(|arg| {
                                format!(
                                    ", {}",
                                    self.sess().source_map().span_to_snippet(arg.span).unwrap()
                                )
                            })
                            .collect::<String>();

                        lint.span_suggestion(
                            sp,
                            "disambiguate the associated function",
                            format!(
                                "{}::{}({}{})",
                                trait_name, segment.ident.name, self_adjusted, args
                            ),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        lint.span_help(
                            sp,
                            &format!(
                                "disambiguate the associated function with `{}::{}(...)`",
                                trait_name, segment.ident,
                            ),
                        );
                    }

                    lint.emit();
                },
            );
        }
    }

    pub(super) fn lint_fully_qualified_call_from_2018(
        &self,
        span: Span,
        method_name: Ident,
        self_ty: Ty<'tcx>,
        self_ty_span: Span,
        expr_id: hir::HirId,
        pick: &Pick<'tcx>,
    ) {
        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        // These are the fully qualified methods added to prelude in Rust 2021
        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
            return;
        }

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        // For from_iter, check if the type actually implements FromIterator.
        // If we know it does not, we don't need to warn.
        if method_name.name == sym::from_iter {
            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
                if !self
                    .infcx
                    .type_implements_trait(
                        trait_def_id,
                        self_ty,
                        InternalSubsts::empty(),
                        self.param_env,
                    )
                    .may_apply()
                {
                    return;
                }
            }
        }

        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
        // since such methods take precedence over trait methods.
        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
            return;
        }

        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
            // "type" refers to either a type or, more likely, a trait from which
            // the associated function or method is from.
            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
            let trait_generics = self.tcx.generics_of(pick.item.container.id());

            let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
            let trait_name = if parameter_count == 0 {
                trait_path
            } else {
                format!(
                    "{}<{}>",
                    trait_path,
                    std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
                )
            };

            let mut lint = lint.build(&format!(
                "trait-associated function `{}` will become ambiguous in Rust 2021",
                method_name.name
            ));

            let self_ty_name = self
                .sess()
                .source_map()
                .span_to_snippet(self_ty_span)
                .unwrap_or_else(|_| self_ty.to_string());

            let self_ty_generics_count = match self_ty.kind() {
                // Get the number of generics the self type has (if an Adt) unless we can determine that
                // the user has written the self type with generics already which we (naively) do by looking
                // for a "<" in `self_ty_name`.
                Adt(def, _) if !self_ty_name.contains('<') => self.tcx.generics_of(def.did).count(),
                _ => 0,
            };
            let self_ty_generics = if self_ty_generics_count > 0 {
                format!("<{}>", vec!["_"; self_ty_generics_count].join(", "))
            } else {
                String::new()
            };
            lint.span_suggestion(
                span,
                "disambiguate the associated function",
                format!(
                    "<{}{} as {}>::{}",
                    self_ty_name, self_ty_generics, trait_name, method_name.name,
                ),
                Applicability::MachineApplicable,
            );

            lint.emit();
        });
    }

    fn trait_path_or_bare_name(
        &self,
        span: Span,
        expr_hir_id: HirId,
        trait_def_id: DefId,
    ) -> String {
        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
            let key = self.tcx.def_key(trait_def_id);
            format!("{}", key.disambiguated_data.data)
        })
    }

    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
        if applicable_trait.import_ids.is_empty() {
            // The trait was declared within the module, we only need to use its name.
            return None;
        }

        let import_items: Vec<_> = applicable_trait
            .import_ids
            .iter()
            .map(|&import_id| {
                let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
                self.tcx.hir().expect_item(hir_id)
            })
            .collect();

        // Find an identifier with which this trait was imported (note that `_` doesn't count).
        let any_id = import_items
            .iter()
            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
            .next();
        if let Some(any_id) = any_id {
            return Some(format!("{}", any_id));
        }

        // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
        // so just take the first one.
        match import_items[0].kind {
            ItemKind::Use(path, _) => Some(
                path.segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join("::"),
            ),
            _ => {
                span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
            }
        }
    }

    /// Creates a string version of the `expr` that includes explicit adjustments.
    /// Returns the string and also a bool indicating whther this is a *precise*
    /// suggestion.
    fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
        let derefs = "*".repeat(pick.autoderefs);

        let autoref = match pick.autoref_or_ptr_adjustment {
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
        };

        let (expr_text, precise) =
            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
                (expr_text, true)
            } else {
                ("(..)".to_string(), false)
            };

        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
            pick.autoref_or_ptr_adjustment
        {
            format!("{}{} as *const _", derefs, expr_text)
        } else {
            format!("{}{}{}", autoref, derefs, expr_text)
        };

        (adjusted_text, precise)
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use anyhow::Result;
use bitflags::*;
use bitvec::{prelude::*, vec::BitVec};
use thiserror::Error;

use crate::{module::Permissions, VA};

const PAGE_SIZE: usize = 0x1000;
const PAGE_SHIFT: usize = 12;
const PAGE_MASK: u64 = 0xFFF;
type PageFrame = [u8; PAGE_SIZE];
const EMPTY_PAGE: PageFrame = [0u8; PAGE_SIZE];

/// Page Frame Number
/// "4 billion pages ought to be enough for everyone!"
/// u32 <= usize for all 32- and 64-bit systems,
/// so you'll some casting to/from usize.
type PFN = u32;

/// A collection of "physical" pages of memory, indexed by `PFN`.
#[derive(Clone)]
struct PageFrames {
    // page frames indexed by `PFN`.
    frames:            Vec<PageFrame>,
    // allocation status, indexed by `PFN`.
    // when `true`, the page is allocated.
    allocation_bitmap: BitVec,
}

impl Default for PageFrames {
    fn default() -> Self {
        PageFrames {
            frames:            vec![],
            allocation_bitmap: bitvec!(),
        }
    }
}

impl PageFrames {
    /// suggest that `page_count` pages will be allocated soon.
    /// useful to avoid frequent reallocations.
    fn reserve(&mut self, page_count: u32) {
        self.frames.reserve(page_count as usize);
        self.allocation_bitmap.reserve(page_count as usize);
    }

    /// allocate a new page frame, returning the PFN.
    /// page frame contents will be empty.
    fn allocate(&mut self) -> PFN {
        let maybe_free_index = self
            .allocation_bitmap
            .iter()
            .enumerate()
            .find(|(_, b)| !**b)
            .map(|(i, _)| i);

        if let Some(pfn) = maybe_free_index {
            self.allocation_bitmap.set(pfn, true);
            pfn as PFN
        } else {
            self.frames.push(EMPTY_PAGE);
            self.allocation_bitmap.push(true);
            (self.frames.len() - 1) as PFN
        }
    }

    /// deallocate a page by its PFN.
    /// panics if the page is not allocated.
    fn deallocate(&mut self, pfn: PFN) {
        assert!(self.allocation_bitmap.get(pfn as usize).unwrap());

        // zero pages upon deallocation.
        self.frames[pfn as usize] = EMPTY_PAGE;
        self.allocation_bitmap.set(pfn as usize, false);
    }
}

impl std::ops::Index<PFN> for PageFrames {
    type Output = PageFrame;

    fn index(&self, index: PFN) -> &PageFrame {
        &self.frames[index as usize]
    }
}

impl std::ops::IndexMut<PFN> for PageFrames {
    fn index_mut(&mut self, index: PFN) -> &mut PageFrame {
        &mut self.frames[index as usize]
    }
}

bitflags! {
    pub struct PageFlags: u32 {
        /// matches [crate::module::Permissions]
        const PERM_R = 0b00000001;
        const PERM_W = 0b00000010;
        const PERM_X = 0b00000100;
        const PERM_RW = Self::PERM_R.bits | Self::PERM_W.bits;
        const PERM_RX =  Self::PERM_R.bits | Self::PERM_X.bits;
        const PERM_WX =  Self::PERM_W.bits | Self::PERM_X.bits;
        const PERM_RWX =  Self::PERM_R.bits | Self::PERM_W.bits | Self::PERM_X.bits;

        /// a zero page, not backed by a Page Frame.
        /// upon write, allocate Page Frame on demand.
        const ZERO = 0b00001000;

        /// upon write, allocate Page Frame, copy frame, update mapping, and do the write.
        const COW = 0b00010000;
    }
}

#[derive(Error, Debug)]
pub enum MMUError {
    #[error("address already mapped: {0:#x}")]
    AddressAlreadyMapped(VA),
    #[error("address not mapped: {0:#x}")]
    AddressNotMapped(VA),
    #[error("address not readable: {0:#x}")]
    AddressNotReadable(VA),
    #[error("address not writable: {0:#x}")]
    AddressNotWritable(VA),
}

#[derive(Default, Clone)]
pub struct MMU {
    pages:   PageFrames,
    mapping: BTreeMap<VA, (PFN, PageFlags)>,
}

fn is_page_aligned(va: VA) -> bool {
    va & PAGE_MASK == 0x0
}

fn page_number(va: VA) -> u64 {
    (va >> PAGE_SHIFT) << PAGE_SHIFT
}

fn page_offset(va: VA) -> usize {
    (va & PAGE_MASK) as usize
}

impl MMU {
    // map memory at the given virtual address, for the given size, with the given
    // perms. panics if `addr` or `size` are not page aligned.
    pub fn mmap(&mut self, addr: VA, size: u64, perms: Permissions) -> Result<()> {
        assert!(is_page_aligned(addr));
        assert!(is_page_aligned(size));

        let page_count = size / PAGE_SIZE as u64;
        assert!(page_count <= u32::MAX as u64);

        // ensure none of the pages are already mapped.
        // Linux mmap updates any existing mappings.
        // I'm not sure if we'd prefer to go that route or not.
        // being conservative here will help us find bugs early on.
        //
        // do this all at once up front to avoid getting
        // half way through and needing to bail.
        for i in 0..page_count {
            let page_va = addr + i * PAGE_SIZE as u64;
            if self.mapping.contains_key(&page_va) {
                return Err(MMUError::AddressAlreadyMapped(page_va).into());
            }
        }

        self.pages.reserve(page_count as u32);

        let flags = PageFlags::ZERO | PageFlags::from_bits_truncate(perms.bits() as u32);
        for i in 0..page_count {
            let page_va = addr + i * PAGE_SIZE as u64;

            // initially, don't allocate any page frames, just use zero pages.
            // only when written to should we allocate page on demand.
            // this should be just as fast, since we've reserved the pages above.
            self.mapping.insert(page_va, (u32::MAX, flags));
        }

        Ok(())
    }

    fn probe_read(&self, addr: VA) -> Result<(PFN, PageFlags)> {
        let (pfn, flags) = match self.mapping.get(&page_number(addr)) {
            Some(&(pfn, flags)) => (pfn, flags),
            None => return Err(MMUError::AddressNotMapped(addr).into()),
        };

        if !flags.intersects(PageFlags::PERM_R) {
            return Err(MMUError::AddressNotReadable(addr).into());
        }

        Ok((pfn, flags))
    }

    pub fn read_u8(&self, addr: VA) -> Result<u8> {
        let (pfn, flags) = self.probe_read(addr)?;

        if flags.intersects(PageFlags::ZERO) {
            return Ok(0);
        }

        let pf = self.pages[pfn];
        Ok(pf[page_offset(addr)])
    }

    pub fn write_u8(&mut self, addr: VA, value: u8) -> Result<()> {
        let (pfn, flags) = match self.mapping.get(&page_number(addr)) {
            Some(&(pfn, flags)) => (pfn, flags),
            None => return Err(MMUError::AddressNotMapped(addr).into()),
        };

        if !flags.intersects(PageFlags::PERM_W) {
            return Err(MMUError::AddressNotWritable(addr).into());
        }

        let pfn = if flags.intersects(PageFlags::ZERO) || flags.intersects(PageFlags::COW) {
            // collect a copy of the existing page frame contents
            let pf = if flags.intersects(PageFlags::ZERO) {
                EMPTY_PAGE
            } else {
                self.pages[pfn].clone()
            };

            // and write it into a newly allocated page frame
            let pfn = self.pages.allocate();
            *(&mut self.pages[pfn]) = pf;

            // now update the mapping to point to the new pf
            let mut flags = flags;
            flags.remove(PageFlags::ZERO);
            flags.remove(PageFlags::COW);

            self.mapping.insert(page_number(addr), (pfn, flags));
            pfn
        } else {
            pfn
        };

        (&mut self.pages[pfn])[page_offset(addr)] = value;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[cfg(test)]
    mod pf {
        use crate::emu::mmu::*;
        use anyhow::Result;

        #[test]
        fn allocate() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs.allocate(), 1);

            Ok(())
        }

        #[test]
        fn deallocate() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs.allocate(), 1);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);

            Ok(())
        }

        #[test]
        fn reserve() -> Result<()> {
            let mut pfs: PageFrames = Default::default();
            pfs.reserve(1);

            // no change in behavior
            assert_eq!(pfs.allocate(), 0);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);

            Ok(())
        }

        #[test]
        fn index() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs[0], EMPTY_PAGE);

            {
                let pf = &mut pfs[0];
                pf[0] = 0xFF;
            }

            assert_ne!(pfs[0], EMPTY_PAGE);

            Ok(())
        }
    }

    #[cfg(test)]
    mod mmu {
        use crate::emu::mmu::*;
        use anyhow::Result;

        #[test]
        fn access_violation() -> Result<()> {
            let mmu: MMU = Default::default();

            assert!(mmu.read_u8(0x0).is_err());
            assert!(mmu.read_u8(0x1).is_err());

            Ok(())
        }

        #[test]
        fn mmap() -> Result<()> {
            let mut mmu: MMU = Default::default();

            assert!(mmu.read_u8(0x1000).is_err());

            mmu.mmap(0x1000, 0x2000, Permissions::R).unwrap();

            assert!(mmu.read_u8(0xFFF).is_err());
            assert_eq!(mmu.read_u8(0x1000).unwrap(), 0x0);
            assert_eq!(mmu.read_u8(0x2000).unwrap(), 0x0);
            assert!(mmu.read_u8(0x3000).is_err());

            Ok(())
        }

        #[test]
        fn write_u8() -> Result<()> {
            let mut mmu: MMU = Default::default();

            assert!(mmu.write_u8(0x1000, 1).is_err());

            mmu.mmap(0x1000, 0x1000, Permissions::R).unwrap();
            mmu.mmap(0x2000, 0x1000, Permissions::RW).unwrap();

            assert!(mmu.write_u8(0x1000, 1).is_err());
            assert_eq!(mmu.read_u8(0x1000).unwrap(), 0);

            assert!(mmu.write_u8(0x2000, 1).is_ok());
            assert_eq!(mmu.read_u8(0x2000).unwrap(), 1);

            Ok(())
        }
    }
}
<commit_msg>mmu: clippy<commit_after>use std::collections::BTreeMap;

use anyhow::Result;
use bitflags::*;
use bitvec::{prelude::*, vec::BitVec};
use thiserror::Error;

use crate::{module::Permissions, VA};

const PAGE_SIZE: usize = 0x1000;
const PAGE_SHIFT: usize = 12;
const PAGE_MASK: u64 = 0xFFF;
type PageFrame = [u8; PAGE_SIZE];
const EMPTY_PAGE: PageFrame = [0u8; PAGE_SIZE];

/// Page Frame Number
/// "4 billion pages ought to be enough for everyone!"
/// u32 <= usize for all 32- and 64-bit systems,
/// so you'll some casting to/from usize.
type PFN = u32;
/// use to flag PFNs that should not be used an indices.
const INVALID_PFN: PFN = u32::MAX;

/// A collection of "physical" pages of memory, indexed by `PFN`.
#[derive(Clone)]
struct PageFrames {
    // page frames indexed by `PFN`.
    frames:            Vec<PageFrame>,
    // allocation status, indexed by `PFN`.
    // when `true`, the page is allocated.
    allocation_bitmap: BitVec,
}

impl Default for PageFrames {
    fn default() -> Self {
        PageFrames {
            frames:            vec![],
            allocation_bitmap: bitvec!(),
        }
    }
}

impl PageFrames {
    /// suggest that `page_count` pages will be allocated soon.
    /// useful to avoid frequent reallocations.
    fn reserve(&mut self, page_count: u32) {
        self.frames.reserve(page_count as usize);
        self.allocation_bitmap.reserve(page_count as usize);
    }

    /// allocate a new page frame, returning the PFN.
    /// page frame contents will be empty.
    fn allocate(&mut self) -> PFN {
        let maybe_free_index = self
            .allocation_bitmap
            .iter()
            .enumerate()
            .find(|(_, b)| !**b)
            .map(|(i, _)| i);

        if let Some(pfn) = maybe_free_index {
            self.allocation_bitmap.set(pfn, true);
            pfn as PFN
        } else {
            self.frames.push(EMPTY_PAGE);
            self.allocation_bitmap.push(true);
            (self.frames.len() - 1) as PFN
        }
    }

    /// deallocate a page by its PFN.
    /// panics if the page is not allocated.
    fn deallocate(&mut self, pfn: PFN) {
        assert!(self.allocation_bitmap.get(pfn as usize).unwrap());

        // zero pages upon deallocation.
        self.frames[pfn as usize] = EMPTY_PAGE;
        self.allocation_bitmap.set(pfn as usize, false);
    }
}

impl std::ops::Index<PFN> for PageFrames {
    type Output = PageFrame;

    fn index(&self, index: PFN) -> &PageFrame {
        &self.frames[index as usize]
    }
}

impl std::ops::IndexMut<PFN> for PageFrames {
    fn index_mut(&mut self, index: PFN) -> &mut PageFrame {
        &mut self.frames[index as usize]
    }
}

bitflags! {
    pub struct PageFlags: u32 {
        /// matches [crate::module::Permissions]
        const PERM_R = 0b00000001;
        const PERM_W = 0b00000010;
        const PERM_X = 0b00000100;
        const PERM_RW = Self::PERM_R.bits | Self::PERM_W.bits;
        const PERM_RX =  Self::PERM_R.bits | Self::PERM_X.bits;
        const PERM_WX =  Self::PERM_W.bits | Self::PERM_X.bits;
        const PERM_RWX =  Self::PERM_R.bits | Self::PERM_W.bits | Self::PERM_X.bits;

        /// a zero page, not backed by a Page Frame.
        /// upon write, allocate Page Frame on demand.
        const ZERO = 0b00001000;

        /// upon write, allocate Page Frame, copy frame, update mapping, and do the write.
        const COW = 0b00010000;
    }
}

#[derive(Error, Debug)]
pub enum MMUError {
    #[error("address already mapped: {0:#x}")]
    AddressAlreadyMapped(VA),
    #[error("address not mapped: {0:#x}")]
    AddressNotMapped(VA),
    #[error("address not readable: {0:#x}")]
    AddressNotReadable(VA),
    #[error("address not writable: {0:#x}")]
    AddressNotWritable(VA),
}

#[derive(Default, Clone)]
pub struct MMU {
    pages:   PageFrames,
    mapping: BTreeMap<VA, (PFN, PageFlags)>,
}

fn is_page_aligned(va: VA) -> bool {
    va & PAGE_MASK == 0x0
}

fn page_number(va: VA) -> u64 {
    (va >> PAGE_SHIFT) << PAGE_SHIFT
}

fn page_offset(va: VA) -> usize {
    (va & PAGE_MASK) as usize
}

impl MMU {
    // map memory at the given virtual address, for the given size, with the given
    // perms. panics if `addr` or `size` are not page aligned.
    pub fn mmap(&mut self, addr: VA, size: u64, perms: Permissions) -> Result<()> {
        assert!(is_page_aligned(addr));
        assert!(is_page_aligned(size));

        let page_count = size / PAGE_SIZE as u64;
        assert!(page_count <= u32::MAX as u64);

        // ensure none of the pages are already mapped.
        // Linux mmap updates any existing mappings.
        // I'm not sure if we'd prefer to go that route or not.
        // being conservative here will help us find bugs early on.
        //
        // do this all at once up front to avoid getting
        // half way through and needing to bail.
        for i in 0..page_count {
            let page_va = addr + i * PAGE_SIZE as u64;
            if self.mapping.contains_key(&page_va) {
                return Err(MMUError::AddressAlreadyMapped(page_va).into());
            }
        }

        self.pages.reserve(page_count as u32);

        let flags = PageFlags::ZERO | PageFlags::from_bits_truncate(perms.bits() as u32);
        for i in 0..page_count {
            let page_va = addr + i * PAGE_SIZE as u64;

            // initially, don't allocate any page frames, just use zero pages.
            // only when written to should we allocate page on demand.
            // this should be just as fast, since we've reserved the pages above.
            self.mapping.insert(page_va, (INVALID_PFN, flags));
        }

        Ok(())
    }

    fn probe_read(&self, addr: VA) -> Result<(PFN, PageFlags)> {
        let (pfn, flags) = match self.mapping.get(&page_number(addr)) {
            Some(&(pfn, flags)) => (pfn, flags),
            None => return Err(MMUError::AddressNotMapped(addr).into()),
        };

        if !flags.intersects(PageFlags::PERM_R) {
            return Err(MMUError::AddressNotReadable(addr).into());
        }

        Ok((pfn, flags))
    }

    pub fn read_u8(&self, addr: VA) -> Result<u8> {
        let (pfn, flags) = self.probe_read(addr)?;

        if flags.intersects(PageFlags::ZERO) {
            // paranoia
            assert!(pfn == INVALID_PFN);
            return Ok(0);
        }

        let pf = self.pages[pfn];
        Ok(pf[page_offset(addr)])
    }

    pub fn write_u8(&mut self, addr: VA, value: u8) -> Result<()> {
        let (pfn, flags) = match self.mapping.get(&page_number(addr)) {
            Some(&(pfn, flags)) => (pfn, flags),
            None => return Err(MMUError::AddressNotMapped(addr).into()),
        };

        if !flags.intersects(PageFlags::PERM_W) {
            return Err(MMUError::AddressNotWritable(addr).into());
        }

        let pfn = if flags.intersects(PageFlags::ZERO) || flags.intersects(PageFlags::COW) {
            // collect a copy of the existing page frame contents
            let pf = if flags.intersects(PageFlags::ZERO) {
                EMPTY_PAGE
            } else {
                self.pages[pfn]
            };

            // and write it into a newly allocated page frame
            let pfn = self.pages.allocate();
            self.pages[pfn] = pf;

            // now update the mapping to point to the new pf
            let mut flags = flags;
            flags.remove(PageFlags::ZERO);
            flags.remove(PageFlags::COW);

            self.mapping.insert(page_number(addr), (pfn, flags));
            pfn
        } else {
            pfn
        };

        (&mut self.pages[pfn])[page_offset(addr)] = value;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[cfg(test)]
    mod pf {
        use crate::emu::mmu::*;
        use anyhow::Result;

        #[test]
        fn allocate() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs.allocate(), 1);

            Ok(())
        }

        #[test]
        fn deallocate() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs.allocate(), 1);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);

            Ok(())
        }

        #[test]
        fn reserve() -> Result<()> {
            let mut pfs: PageFrames = Default::default();
            pfs.reserve(1);

            // no change in behavior
            assert_eq!(pfs.allocate(), 0);
            pfs.deallocate(0);
            assert_eq!(pfs.allocate(), 0);

            Ok(())
        }

        #[test]
        fn index() -> Result<()> {
            let mut pfs: PageFrames = Default::default();

            assert_eq!(pfs.allocate(), 0);
            assert_eq!(pfs[0], EMPTY_PAGE);

            {
                let pf = &mut pfs[0];
                pf[0] = 0xFF;
            }

            assert_ne!(pfs[0], EMPTY_PAGE);

            Ok(())
        }
    }

    #[cfg(test)]
    mod mmu {
        use crate::emu::mmu::*;
        use anyhow::Result;

        #[test]
        fn access_violation() -> Result<()> {
            let mmu: MMU = Default::default();

            assert!(mmu.read_u8(0x0).is_err());
            assert!(mmu.read_u8(0x1).is_err());

            Ok(())
        }

        #[test]
        fn mmap() -> Result<()> {
            let mut mmu: MMU = Default::default();

            assert!(mmu.read_u8(0x1000).is_err());

            mmu.mmap(0x1000, 0x2000, Permissions::R).unwrap();

            assert!(mmu.read_u8(0xFFF).is_err());
            assert_eq!(mmu.read_u8(0x1000).unwrap(), 0x0);
            assert_eq!(mmu.read_u8(0x2000).unwrap(), 0x0);
            assert!(mmu.read_u8(0x3000).is_err());

            Ok(())
        }

        #[test]
        fn write_u8() -> Result<()> {
            let mut mmu: MMU = Default::default();

            assert!(mmu.write_u8(0x1000, 1).is_err());

            mmu.mmap(0x1000, 0x1000, Permissions::R).unwrap();
            mmu.mmap(0x2000, 0x1000, Permissions::RW).unwrap();

            assert!(mmu.write_u8(0x1000, 1).is_err());
            assert_eq!(mmu.read_u8(0x1000).unwrap(), 0);

            assert!(mmu.write_u8(0x2000, 1).is_ok());
            assert_eq!(mmu.read_u8(0x2000).unwrap(), 1);

            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>use std::error::{Error, FromError};
use std::fmt::{self, Display, Formatter};
use std::old_io::IoError;

use hyper::client::Client;
use hyper::header::Headers;
use hyper::HttpError;

// Content of the request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the SOAPAction header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// Errors
pub enum RequestError {
    HttpError(HttpError),
    InvalidResponse,
    IoError(IoError),
}

impl Display for RequestError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => err.fmt(f),
            RequestError::InvalidResponse => write!(f, "Invalid response received from router."), // TODO const
            RequestError::IoError(ref err) => err.fmt(f),
        }
    }
}

impl FromError<IoError> for RequestError {
    fn from_error(err: IoError) -> RequestError {
        RequestError::IoError(err)
    }
}

impl FromError<HttpError> for RequestError {
    fn from_error(err: HttpError) -> RequestError {
        RequestError::HttpError(err)
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::InvalidResponse => "Invalid response received from router.", // TODO const
            RequestError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            RequestError::HttpError(ref err) => err.cause(),
            RequestError::InvalidResponse => None,
            RequestError::IoError(ref err) => err.cause(),
        }
    }
}

// Get the external IP address.
// TODO return IpAddr instead of String
pub fn get_external_ip(url: &str) -> Result<String, RequestError>  {
    let mut client = Client::new();

    let mut headers = Headers::new();
    headers.set_raw("SOAPAction", vec![String::from_str(SOAP_ACTION).into_bytes()]); // TODO clean-up

    let mut builder = client.post(url);
    builder = builder.headers(headers);
    builder = builder.body(EXTERNAL_IP_REQUEST);

    let mut res = try!(builder.send());
    let text = try!(res.read_to_string());
    match extract_address(text) {
        None => Err(RequestError::InvalidResponse),
        Some(addr) => Ok(addr),
    }
}

// Extract the address from the text.
fn extract_address(text: String) -> Option<String> {
    let re = regex!(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>");
    match re.captures(text.as_slice()) {
        None => None,
        Some(cap) => {
            match cap.at(1) {
                None => None,
                Some(ip) => Some(ip.to_string()),
            }
        },
    }
}
<commit_msg>Improve code and error handling.<commit_after>use std::error::{Error, FromError};
use std::fmt::{self, Display, Formatter};
use std::old_io::IoError;

use hyper::client::Client;
use hyper::header::Headers;
use hyper::HttpError;

// Content of the request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the SOAPAction header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// Errors
pub enum RequestError {
    HttpError(HttpError),
    InvalidResponse,
    IoError(IoError),
}

impl Display for RequestError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => err.fmt(f),
            RequestError::InvalidResponse => write!(f, "Invalid response received from router."), // TODO const
            RequestError::IoError(ref err) => err.fmt(f),
        }
    }
}

impl FromError<IoError> for RequestError {
    fn from_error(err: IoError) -> RequestError {
        RequestError::IoError(err)
    }
}

impl FromError<HttpError> for RequestError {
    fn from_error(err: HttpError) -> RequestError {
        RequestError::HttpError(err)
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::InvalidResponse => "Invalid response received from router.", // TODO const
            RequestError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            RequestError::HttpError(ref err) => err.cause(),
            RequestError::InvalidResponse => None,
            RequestError::IoError(ref err) => err.cause(),
        }
    }
}

// Get the external IP address.
// TODO return IpAddr instead of String
pub fn get_external_ip(url: &str) -> Result<String, RequestError>  {
    let mut client = Client::new();

    let mut headers = Headers::new();
    headers.set_raw("SOAPAction", vec![String::from_str(SOAP_ACTION).into_bytes()]); // TODO clean-up

    let mut builder = client.post(url);
    builder = builder.headers(headers);
    builder = builder.body(EXTERNAL_IP_REQUEST);

    let mut res = try!(builder.send());
    let text = try!(res.read_to_string());
    extract_address(text)
}

// Extract the address from the text.
fn extract_address(text: String) -> Result<String, RequestError> {
    let re = regex!(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>");
    match re.captures(text.as_slice()) {
        None => Err(RequestError::InvalidResponse),
        Some(cap) => {
            match cap.at(1) {
                None => Err(RequestError::InvalidResponse),
                Some(ip) => Ok(ip.to_string()),
            }
        },
    }
}
<|endoftext|>


<commit_before><commit_msg>remove borrow<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            println!("nlen {}", nlen);
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.iter_mut() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.iter_mut() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        fail!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<commit_msg>remove silly println that snuck in<commit_after>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.iter_mut() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.iter_mut() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        fail!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<|endoftext|>


<commit_before>use prometheus::{Counter, Gauge};
use std::time::Instant;

pub struct StartInstant(pub Instant);

pub struct Varz {
    pub start_instant: StartInstant,
    pub uptime: Gauge,
    pub cache_frequent_len: Gauge,
    pub cache_recent_len: Gauge,
    pub cache_test_len: Gauge,
    pub cache_inserted: Gauge,
    pub cache_evicted: Gauge,
    pub client_qps: Gauge,
    pub client_queries: Gauge,
    pub client_queries_udp: Counter,
    pub client_queries_tcp: Counter,
    pub client_queries_cached: Counter,
    pub client_queries_expired: Counter,
    pub client_queries_errors: Counter,
    pub upstream_errors: Counter,
    pub upstream_received: Counter,
    pub upstream_timeout: Counter,
}

impl Varz {
    pub fn new() -> Varz {
        Varz {
            start_instant: StartInstant::default(),
            uptime: register_gauge!(opts!("edgedns_uptime",
                                          "Uptime",
                                          labels!{"handler" => "all",}))
                .unwrap(),
            cache_frequent_len: register_gauge!(opts!("edgedns_cache_frequent_len",
                                                      "Number of entries in the cached set of \
                                                       frequent items",
                                                      labels!{"handler" => "all",}))
                .unwrap(),
            cache_recent_len: register_gauge!(opts!("edgedns_cache_recent_len",
                                                    "Number of entries in the cached set of \
                                                     recent items",
                                                    labels!{"handler" => "all",}))
                .unwrap(),
            cache_test_len: register_gauge!(opts!("edgedns_cache_test_len",
                                                  "Number of entries in the cached set of \
                                                   staged items",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            cache_inserted: register_gauge!(opts!("edgedns_cache_inserted",
                                                  "Number of entries added to the cache",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            cache_evicted: register_gauge!(opts!("edgedns_cache_evicted",
                                                 "Number of entries evicted from the cache",
                                                 labels!{"handler" => "all",}))
                .unwrap(),
            client_qps: register_gauge!(opts!("edgedns_client_qps",
                                              "Average number of client queries per second",
                                              labels!{"handler" => "all",}))
                .unwrap(),
            client_queries: register_gauge!(opts!("edgedns_client_queries",
                                                  "Number of client queries received",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_udp: register_counter!(opts!("edgedns_client_queries_udp",
                                                        "Number of client queries received \
                                                         using UDP",
                                                        labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_tcp: register_counter!(opts!("edgedns_client_queries_tcp",
                                                        "Number of client queries received \
                                                         using TCP",
                                                        labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_cached: register_counter!(opts!("edgedns_client_queries_cached",
                                                           "Number of client queries sent from \
                                                            the cache",
                                                           labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_expired: register_counter!(opts!("edgedns_client_queries_expired",
                                                            "Number of expired client queries",
                                                            labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_errors: register_counter!(opts!("edgedns_client_queries_errors",
                                                           "Number of bogus client queries",
                                                           labels!{"handler" => "all",}))
                .unwrap(),
            upstream_errors: register_counter!(opts!("edgedns_upstream_errors",
                                                     "Number of bogus upstream servers responses",
                                                     labels!{"handler" => "all",}))
                .unwrap(),
            upstream_received: register_counter!(opts!("edgedns_upstream_received",
                                                       "Number of upstream servers responses",
                                                       labels!{"handler" => "all",}))
                .unwrap(),
            upstream_timeout: register_counter!(opts!("edgedns_upstream_timeout",
                                                      "Number of upstream servers responses \
                                                       having timed out",
                                                      labels!{"handler" => "all",}))
                .unwrap(),
        }
    }
}

impl Default for StartInstant {
    fn default() -> StartInstant {
        StartInstant(Instant::now())
    }
}
<commit_msg>Add a Default trait to Varz<commit_after>use prometheus::{Counter, Gauge};
use std::time::Instant;

pub struct StartInstant(pub Instant);

pub struct Varz {
    pub start_instant: StartInstant,
    pub uptime: Gauge,
    pub cache_frequent_len: Gauge,
    pub cache_recent_len: Gauge,
    pub cache_test_len: Gauge,
    pub cache_inserted: Gauge,
    pub cache_evicted: Gauge,
    pub client_qps: Gauge,
    pub client_queries: Gauge,
    pub client_queries_udp: Counter,
    pub client_queries_tcp: Counter,
    pub client_queries_cached: Counter,
    pub client_queries_expired: Counter,
    pub client_queries_errors: Counter,
    pub upstream_errors: Counter,
    pub upstream_received: Counter,
    pub upstream_timeout: Counter,
}

impl Varz {
    pub fn new() -> Varz {
        Varz {
            start_instant: StartInstant::default(),
            uptime: register_gauge!(opts!("edgedns_uptime",
                                          "Uptime",
                                          labels!{"handler" => "all",}))
                .unwrap(),
            cache_frequent_len: register_gauge!(opts!("edgedns_cache_frequent_len",
                                                      "Number of entries in the cached set of \
                                                       frequent items",
                                                      labels!{"handler" => "all",}))
                .unwrap(),
            cache_recent_len: register_gauge!(opts!("edgedns_cache_recent_len",
                                                    "Number of entries in the cached set of \
                                                     recent items",
                                                    labels!{"handler" => "all",}))
                .unwrap(),
            cache_test_len: register_gauge!(opts!("edgedns_cache_test_len",
                                                  "Number of entries in the cached set of \
                                                   staged items",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            cache_inserted: register_gauge!(opts!("edgedns_cache_inserted",
                                                  "Number of entries added to the cache",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            cache_evicted: register_gauge!(opts!("edgedns_cache_evicted",
                                                 "Number of entries evicted from the cache",
                                                 labels!{"handler" => "all",}))
                .unwrap(),
            client_qps: register_gauge!(opts!("edgedns_client_qps",
                                              "Average number of client queries per second",
                                              labels!{"handler" => "all",}))
                .unwrap(),
            client_queries: register_gauge!(opts!("edgedns_client_queries",
                                                  "Number of client queries received",
                                                  labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_udp: register_counter!(opts!("edgedns_client_queries_udp",
                                                        "Number of client queries received \
                                                         using UDP",
                                                        labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_tcp: register_counter!(opts!("edgedns_client_queries_tcp",
                                                        "Number of client queries received \
                                                         using TCP",
                                                        labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_cached: register_counter!(opts!("edgedns_client_queries_cached",
                                                           "Number of client queries sent from \
                                                            the cache",
                                                           labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_expired: register_counter!(opts!("edgedns_client_queries_expired",
                                                            "Number of expired client queries",
                                                            labels!{"handler" => "all",}))
                .unwrap(),
            client_queries_errors: register_counter!(opts!("edgedns_client_queries_errors",
                                                           "Number of bogus client queries",
                                                           labels!{"handler" => "all",}))
                .unwrap(),
            upstream_errors: register_counter!(opts!("edgedns_upstream_errors",
                                                     "Number of bogus upstream servers responses",
                                                     labels!{"handler" => "all",}))
                .unwrap(),
            upstream_received: register_counter!(opts!("edgedns_upstream_received",
                                                       "Number of upstream servers responses",
                                                       labels!{"handler" => "all",}))
                .unwrap(),
            upstream_timeout: register_counter!(opts!("edgedns_upstream_timeout",
                                                      "Number of upstream servers responses \
                                                       having timed out",
                                                      labels!{"handler" => "all",}))
                .unwrap(),
        }
    }
}

impl Default for Varz {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for StartInstant {
    fn default() -> StartInstant {
        StartInstant(Instant::now())
    }
}
<|endoftext|>