<commit_before>use rustc::ty;
use rustc::hir::def_id::DefId;
use rustc::lint::{LintContext, Lint, LateContext};
use rustc::hir::Expr_::*;
use rustc::hir::Expr;
use rustc::hir::def::Def;

use syntax::symbol;
use syntax_pos::Span;

const ROCKET_TYPE: &'static [&'static str] = &["rocket", "rocket", "Rocket"];

const ROCKET_IGNITE_FN: &'static [&'static str] = &["rocket", "ignite"];
const ROCKET_IGNITE_STATIC: &'static [&'static str] = &["rocket", "rocket",
                                                        "Rocket", "ignite"];

const ROCKET_CUSTOM_FN: &'static [&'static str] = &["rocket", "custom"];
const ROCKET_CUSTOM_STATIC: &'static [&'static str] = &["rocket", "rocket",
                                                        "Rocket", "custom"];

const ABSOLUTE: &'static ty::item_path::RootMode =
    &ty::item_path::RootMode::Absolute;

/// Check if a `DefId`'s path matches the given absolute type path usage.
pub fn match_def_path(tcx: ty::TyCtxt, def_id: DefId, path: &[&str]) -> bool {
    struct AbsolutePathBuffer {
        names: Vec<symbol::InternedString>,
    }

    impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer {
        fn root_mode(&self) -> &ty::item_path::RootMode {
            ABSOLUTE
        }

        fn push(&mut self, text: &str) {
            self.names.push(symbol::Symbol::intern(text).as_str());
        }
    }

    let mut apb = AbsolutePathBuffer { names: vec![] };
    tcx.push_item_path(&mut apb, def_id);

    apb.names.len() == path.len() &&
    apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b)
}

/// Check if the method call given in `expr` belongs to given type.
pub fn is_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
    let method_call = ty::MethodCall::expr(expr.id);

    let trt_id = cx.tables
        .method_map
        .get(&method_call)
        .and_then(|callee| cx.tcx.impl_of_method(callee.def_id));

    if let Some(trt_id) = trt_id {
        match_def_path(cx.tcx, trt_id, path)
    } else {
        false
    }
}

pub fn find_initial_receiver<'e>(cx: &LateContext,
                                 expr: &'e Expr)
                                 -> Option<&'e Expr> {
    match expr.node {
        ExprMethodCall(_, _, ref args) => find_initial_receiver(cx, &args[0]),
        ExprCall(..) if is_rocket_start_call(cx, expr) => Some(expr),
        ExprCall(ref call, _) => find_initial_receiver(cx, call),
        ExprPath(_) => Some(expr),
        _ => None,
    }
}

pub fn rocket_method_call<'e>(method: &str,
                              cx: &LateContext,
                              expr: &'e Expr)
                              -> (Option<(Option<&'e Expr>, &'e [Expr])>) {
    if let ExprMethodCall(ref name, _, ref exprs) = expr.node {
        if &*name.node.as_str() == method && is_impl_method(cx, expr, ROCKET_TYPE) {
            let receiver = find_initial_receiver(cx, &exprs[0]);
            return Some((receiver, &exprs[1..]));
        }
    }

    None
}

pub fn is_rocket_start_call(cx: &LateContext, expr: &Expr) -> bool {
    if let ExprCall(ref expr, ..) = expr.node {
        if let ExprPath(ref qpath) = expr.node {
            let def_id = cx.tables.qpath_def(qpath, expr.id).def_id();
            if match_def_path(cx.tcx, def_id, ROCKET_IGNITE_FN) {
                return true;
            } else if match_def_path(cx.tcx, def_id, ROCKET_IGNITE_STATIC) {
                return true;
            } else if match_def_path(cx.tcx, def_id, ROCKET_CUSTOM_FN) {
                return true;
            } else if is_impl_method(cx, expr, ROCKET_CUSTOM_STATIC) {
                return true;
            }
        }
    }

    false
}

pub fn extract_mount_fn_def_ids(cx: &LateContext, expr: &Expr) -> Vec<DefId> {
    let mut output = Vec::new();
    // Call to into_vec
    if let ExprCall(_, ref args) = expr.node {
        if let Some(&ExprBox(ref expr)) = args.iter().next().map(|e| &e.node) {
            // Array of routes.
            if let ExprArray(ref members) = expr.node {
                for expr in members.iter() {
                    // Route::From call
                    if let ExprCall(_, ref args) = expr.node {
                        if args.len() < 1 {
                            continue;
                        }

                        // address of info struct
                        if let ExprAddrOf(_, ref expr) = args[0].node {
                            // path to info_struct
                            if let ExprPath(ref qpath) = expr.node {
                                let def = cx.tables.qpath_def(qpath, expr.id);
                                output.push(def.def_id());
                            }
                        }
                    }
                }
            }
        }
    }

    output
}

pub fn returns_rocket_instance(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(ref ty) = cx.tables.expr_ty_opt(expr) {
        if let Some(def_id) = ty.ty_to_def_id() {
            if match_def_path(cx.tcx, def_id, ROCKET_TYPE) {
                return true;
            }
        }
    }

    false
}

pub trait DefExt {
    fn def_id_opt(&self) -> Option<DefId>;
}

impl DefExt for Def {
    fn def_id_opt(&self) -> Option<DefId> {
        match *self {
            Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | Def::Variant(id)
                | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id)
                | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id)
                | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id)
                | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id)
                | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => Some(id),
            Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
        }
    }
}

pub fn msg_and_help<'a, T: LintContext<'a>>(cx: &T,
                                            lint: &'static Lint,
                                            msg_sp: Span,
                                            msg: &str,
                                            note: &str,
                                            help_sp: Option<Span>,
                                            help: &str) {
    let mut b = cx.struct_span_lint(lint, msg_sp, msg);
    b.note(note);
    if let Some(span) = help_sp {
        b.span_help(span, help);
    }

    b.emit();
}
<commit_msg>Fix lints for latest nightly.<commit_after>use rustc::ty;
use rustc::hir::def_id::DefId;
use rustc::lint::{LintContext, Lint, LateContext};
use rustc::hir::Expr_::*;
use rustc::hir::Expr;
use rustc::hir::def::Def;

use syntax::symbol;
use syntax_pos::Span;

const ROCKET_TYPE: &'static [&'static str] = &["rocket", "rocket", "Rocket"];

const ROCKET_IGNITE_FN: &'static [&'static str] = &["rocket", "ignite"];
const ROCKET_IGNITE_STATIC: &'static [&'static str] = &["rocket", "rocket",
                                                        "Rocket", "ignite"];

const ROCKET_CUSTOM_FN: &'static [&'static str] = &["rocket", "custom"];
const ROCKET_CUSTOM_STATIC: &'static [&'static str] = &["rocket", "rocket",
                                                        "Rocket", "custom"];

const ABSOLUTE: &'static ty::item_path::RootMode =
    &ty::item_path::RootMode::Absolute;

/// Check if a `DefId`'s path matches the given absolute type path usage.
pub fn match_def_path(tcx: ty::TyCtxt, def_id: DefId, path: &[&str]) -> bool {
    struct AbsolutePathBuffer {
        names: Vec<symbol::InternedString>,
    }

    impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer {
        fn root_mode(&self) -> &ty::item_path::RootMode {
            ABSOLUTE
        }

        fn push(&mut self, text: &str) {
            self.names.push(symbol::Symbol::intern(text).as_str());
        }
    }

    let mut apb = AbsolutePathBuffer { names: vec![] };
    tcx.push_item_path(&mut apb, def_id);

    apb.names.len() == path.len() &&
    apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b)
}

/// Check if the method call given in `expr` belongs to given type.
pub fn is_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool {
    let method_call = ty::MethodCall::expr(expr.id);

    let trt_id = cx.tables
        .method_map
        .get(&method_call)
        .and_then(|callee| cx.tcx.impl_of_method(callee.def_id));

    if let Some(trt_id) = trt_id {
        match_def_path(cx.tcx, trt_id, path)
    } else {
        false
    }
}

pub fn find_initial_receiver<'e>(cx: &LateContext,
                                 expr: &'e Expr)
                                 -> Option<&'e Expr> {
    match expr.node {
        ExprMethodCall(_, _, ref args) => find_initial_receiver(cx, &args[0]),
        ExprCall(..) if is_rocket_start_call(cx, expr) => Some(expr),
        ExprCall(ref call, _) => find_initial_receiver(cx, call),
        ExprPath(_) => Some(expr),
        _ => None,
    }
}

pub fn rocket_method_call<'e>(method: &str,
                              cx: &LateContext,
                              expr: &'e Expr)
                              -> (Option<(Option<&'e Expr>, &'e [Expr])>) {
    if let ExprMethodCall(ref name, _, ref exprs) = expr.node {
        if &*name.node.as_str() == method && is_impl_method(cx, expr, ROCKET_TYPE) {
            let receiver = find_initial_receiver(cx, &exprs[0]);
            return Some((receiver, &exprs[1..]));
        }
    }

    None
}

pub fn is_rocket_start_call(cx: &LateContext, expr: &Expr) -> bool {
    if let ExprCall(ref expr, ..) = expr.node {
        if let ExprPath(ref qpath) = expr.node {
            let def_id = cx.tables.qpath_def(qpath, expr.id).def_id();
            if match_def_path(cx.tcx, def_id, ROCKET_IGNITE_FN) {
                return true;
            } else if match_def_path(cx.tcx, def_id, ROCKET_IGNITE_STATIC) {
                return true;
            } else if match_def_path(cx.tcx, def_id, ROCKET_CUSTOM_FN) {
                return true;
            } else if is_impl_method(cx, expr, ROCKET_CUSTOM_STATIC) {
                return true;
            }
        }
    }

    false
}

pub fn extract_mount_fn_def_ids(cx: &LateContext, expr: &Expr) -> Vec<DefId> {
    let mut output = Vec::new();
    // Call to into_vec
    if let ExprCall(_, ref args) = expr.node {
        if let Some(&ExprBox(ref expr)) = args.iter().next().map(|e| &e.node) {
            // Array of routes.
            if let ExprArray(ref members) = expr.node {
                for expr in members.iter() {
                    // Route::From call
                    if let ExprCall(_, ref args) = expr.node {
                        if args.len() < 1 {
                            continue;
                        }

                        // address of info struct
                        if let ExprAddrOf(_, ref expr) = args[0].node {
                            // path to info_struct
                            if let ExprPath(ref qpath) = expr.node {
                                let def = cx.tables.qpath_def(qpath, expr.id);
                                output.push(def.def_id());
                            }
                        }
                    }
                }
            }
        }
    }

    output
}

pub fn returns_rocket_instance(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(ref ty) = cx.tables.expr_ty_opt(expr) {
        if let Some(def_id) = ty.ty_to_def_id() {
            if match_def_path(cx.tcx, def_id, ROCKET_TYPE) {
                return true;
            }
        }
    }

    false
}

pub trait DefExt {
    fn def_id_opt(&self) -> Option<DefId>;
}

impl DefExt for Def {
    fn def_id_opt(&self) -> Option<DefId> {
        match *self {
            Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | Def::Variant(id)
                | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id)
                | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id)
                | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id)
                | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id)
                | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..)
                | Def::GlobalAsm(id) => Some(id),
            Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
        }
    }
}

pub fn msg_and_help<'a, T: LintContext<'a>>(cx: &T,
                                            lint: &'static Lint,
                                            msg_sp: Span,
                                            msg: &str,
                                            note: &str,
                                            help_sp: Option<Span>,
                                            help: &str) {
    let mut b = cx.struct_span_lint(lint, msg_sp, msg);
    b.note(note);
    if let Some(span) = help_sp {
        b.span_help(span, help);
    }

    b.emit();
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! strcmp_tests {
    ( $TestRegion:path ) => {
        use libc::{c_char, c_int, c_void, strcmp, uint64_t};
        use lucet_runtime::vmctx::lucet_vmctx;
        use lucet_runtime::{lucet_hostcalls, Error, Limits, Region, Val, WASM_PAGE_SIZE};
        use std::ffi::CString;
        use std::sync::Arc;
        use $TestRegion as TestRegion;
        use $crate::build::test_module_c;

        lucet_hostcalls! {
            #[no_mangle]
            pub unsafe extern "C" fn hostcall_host_fault(
                &mut _vmctx,
            ) -> () {
                let oob = (-1isize) as *mut c_char;
                *oob = 'x' as c_char;
            }
        }

        fn strcmp_compare(s1: &str, s2: &str) {
            let s1 = CString::new(s1)
                .expect("s1 is a valid CString")
                .into_bytes_with_nul();
            let s2 = CString::new(s2)
                .expect("s2 is a valid CString")
                .into_bytes_with_nul();

            assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize);

            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds");
            let heap = inst.heap_mut();

            let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize;
            let s2_ptr = s1_ptr + s1.len();
            heap[s1_ptr..s2_ptr].copy_from_slice(&s1);
            heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2);

            let res = c_int::from(
                inst.run(
                    "run_strcmp",
                    &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)],
                )
                .expect("instance runs"),
            );

            let host_strcmp_res =
                unsafe { strcmp(s1.as_ptr() as *const c_char, s2.as_ptr() as *const c_char) };
            assert_eq!(res, host_strcmp_res);
        }

        #[test]
        fn strcmp_abc_abc() {
            strcmp_compare("abc", "abc");
        }

        #[test]
        fn strcmp_def_abc() {
            strcmp_compare("def", "abc");
        }

        #[test]
        fn strcmp_abcd_abc() {
            strcmp_compare("abcd", "abc");
        }

        #[test]
        fn strcmp_abc_abcd() {
            strcmp_compare("abc", "abcd");
        }

        #[test]
        fn strcmp_fault_test() {
            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            match inst.run("wasm_fault", &[]) {
                Err(Error::RuntimeFault { .. }) => (),
                res => panic!("unexpected result: {:?}", res),
            }
        }
    };
}
<commit_msg>lucet-runtime-tests: fix warning<commit_after>#[macro_export]
macro_rules! strcmp_tests {
    ( $TestRegion:path ) => {
        use libc::{c_char, c_int, c_void, strcmp};
        use lucet_runtime::vmctx::lucet_vmctx;
        use lucet_runtime::{lucet_hostcalls, Error, Limits, Region, Val, WASM_PAGE_SIZE};
        use std::ffi::CString;
        use std::sync::Arc;
        use $TestRegion as TestRegion;
        use $crate::build::test_module_c;

        lucet_hostcalls! {
            #[no_mangle]
            pub unsafe extern "C" fn hostcall_host_fault(
                &mut _vmctx,
            ) -> () {
                let oob = (-1isize) as *mut c_char;
                *oob = 'x' as c_char;
            }
        }

        fn strcmp_compare(s1: &str, s2: &str) {
            let s1 = CString::new(s1)
                .expect("s1 is a valid CString")
                .into_bytes_with_nul();
            let s2 = CString::new(s2)
                .expect("s2 is a valid CString")
                .into_bytes_with_nul();

            assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize);

            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds");
            let heap = inst.heap_mut();

            let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize;
            let s2_ptr = s1_ptr + s1.len();
            heap[s1_ptr..s2_ptr].copy_from_slice(&s1);
            heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2);

            let res = c_int::from(
                inst.run(
                    "run_strcmp",
                    &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)],
                )
                .expect("instance runs"),
            );

            let host_strcmp_res =
                unsafe { strcmp(s1.as_ptr() as *const c_char, s2.as_ptr() as *const c_char) };
            assert_eq!(res, host_strcmp_res);
        }

        #[test]
        fn strcmp_abc_abc() {
            strcmp_compare("abc", "abc");
        }

        #[test]
        fn strcmp_def_abc() {
            strcmp_compare("def", "abc");
        }

        #[test]
        fn strcmp_abcd_abc() {
            strcmp_compare("abcd", "abc");
        }

        #[test]
        fn strcmp_abc_abcd() {
            strcmp_compare("abc", "abcd");
        }

        #[test]
        fn strcmp_fault_test() {
            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            match inst.run("wasm_fault", &[]) {
                Err(Error::RuntimeFault { .. }) => (),
                res => panic!("unexpected result: {:?}", res),
            }
        }
    };
}
<|endoftext|>


<commit_before>use wire::handler::{PeerId, PeerAction, ServerHandler};
use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;
use file::PartialFile;
use std::collections::HashMap;
use wire::data::PeerMsg;
use std::time::SystemTime;
use file::{PartialFileTrait, PeerFile};

const TIMEOUT_SECONDS: u64 = 60 * 5;
const KEEPALIVE_PERIOD: u64 = 30;

pub struct PeerState {
    has_handshake: bool,
    disconnected: bool,
    peer_choking: bool,
    peer_interested: bool,
    am_choking: bool,
    am_interested: bool,
    last_keepalive_recvd: SystemTime,
    last_keepalive_sent: SystemTime,
    last_msg_time: SystemTime,
    file: PeerFile,
}

impl PeerState {
    pub fn new(len: usize) -> PeerState {
        PeerState {
            has_handshake: false,
            disconnected: false,
            peer_choking: true,
            peer_interested: false,
            am_choking: true,
            am_interested: false,
            last_keepalive_recvd: SystemTime::now(),
            last_keepalive_sent: SystemTime::now(),
            last_msg_time: SystemTime::now(),
            file: PeerFile::new(len),
        }
    }
}

pub struct PeerServer {
    peers: HashMap<PeerId, PeerState>,
    hash: SHA1Hash20b,
    our_peer_id: String,
    partial_file: PartialFile,
}

const PROTOCOL_ID: &'static str = "rustorrent-beta";

impl ServerHandler for PeerServer {
    fn new(metainfo: MetaInfo, hash: SHA1Hash20b, our_peer_id: &str) -> Self {
        let partial_file = PartialFile::new(&metainfo.info);

        PeerServer {
            peers: HashMap::new(),
            hash: hash,
            our_peer_id: our_peer_id.to_string(),
            partial_file: partial_file,
        }
    }

    fn on_peer_connect(&mut self, id: PeerId) -> PeerAction {
        let handshake = PeerMsg::handshake(PROTOCOL_ID.to_string(),
                                           self.our_peer_id.to_string(),
                                           &self.hash);
        PeerAction::SendMessages(vec![handshake])
    }

    fn on_message_receive(&mut self, id: PeerId, msg: PeerMsg) -> PeerAction {
        {
            let peer = match self.peers.get_mut(&id) {
                Some(peer) => peer,
                None => return PeerAction::Nothing,
            };

            if peer.disconnected {
                return PeerAction::Nothing;
            }

            peer.last_msg_time = SystemTime::now();

            if !peer.has_handshake {
                match msg {
                    PeerMsg::HandShake(_, ref their_hash, _) => {
                        if their_hash == &self.hash {
                            peer.has_handshake = true;
                        } else {
                            peer.disconnected = true;
                            return PeerAction::Disconnect;
                        }
                    }
                    _ => {
                        peer.disconnected = true;
                    }
                }
            }
        }

        let mut outgoing_msgs = Vec::new();
        let mut handled = true;

        {
            let peer = match self.peers.get_mut(&id) {
                Some(peer) => peer,
                None => return PeerAction::Nothing,
            };

            // messages that mutate the peer
            match msg {
                PeerMsg::HandShake(..) => {}
                PeerMsg::KeepAlive => peer.last_keepalive_recvd = SystemTime::now(),
                PeerMsg::Choke => {
                    peer.peer_choking = true;
                }
                PeerMsg::Unchoke => {
                    peer.peer_choking = false;
                }
                PeerMsg::Interested => {
                    peer.peer_interested = true;
                }
                PeerMsg::NotInterested => {
                    peer.peer_interested = false;
                }
                PeerMsg::Have(index) => peer.file.set(index as usize, true),
                PeerMsg::Bitfield(_) => {}
                _ => handled = false,
            };
        }

        // messages that don't need to mutate peer
        let choking = {
            match self.peers.get(&id) {
                Some(peer) => peer.am_choking,
                None => return PeerAction::Nothing,
            }
        };

        if !choking && !handled {
            match msg {
                PeerMsg::Request(index, begin, offset) => {
                    let response = self._get_piece_from_req(index as usize, begin, offset);
                    if response.is_some() {
                        outgoing_msgs.push(response.unwrap());
                    }
                }
                PeerMsg::Piece(index, begin, block) => {
                    self.partial_file.add_piece(index as usize, begin as usize, block);
                }
                PeerMsg::Cancel(..) => {}
                PeerMsg::Port(_) => {}
                _ => handled = true,
            }
        }

        if outgoing_msgs.len() > 0 {
            PeerAction::SendMessages(outgoing_msgs)
        } else {
            PeerAction::Nothing
        }
    }

    fn on_peer_disconnect(&mut self, id: PeerId) -> PeerAction {
        self.peers.remove(&id);
        PeerAction::Nothing
    }

    // remove peers that have no replied in five minutes
    fn on_loop(&mut self) -> PeerAction {
        self._remove_old_peers();
        PeerAction::Nothing
    }
}

impl PeerServer {
    fn _remove_old_peers(&mut self) {
        let for_removal = self._get_timeout_ids();

        for id in for_removal {
            self.peers.remove(&id);
        }

    }

    fn _get_timeout_ids(&self) -> Vec<PeerId> {
        let mut for_removal = Vec::new();
        for (&id, peer) in &self.peers {
            match peer.last_keepalive_recvd.elapsed() {
                Ok(duration) => {
                    if duration.as_secs() > TIMEOUT_SECONDS {
                        for_removal.push(id);
                    }
                }
                _ => (),
            }
        }
        for_removal
    }

    fn _get_keepalive_ids(&self) -> Vec<PeerId> {
        let mut for_keeping = Vec::new();
        for (&id, peer) in &self.peers {
            match peer.last_msg_time.elapsed() {
                Ok(duration) => {
                    if duration.as_secs() > KEEPALIVE_PERIOD {
                        for_keeping.push(id);
                    }
                }
                _ => (),
            }
        }
        for_keeping
    }

    fn _get_piece_from_req(&mut self, index: usize, begin: u32, offset: u32) -> Option<PeerMsg> {
        if self.partial_file.has_piece(index as usize) {
            let piece = self.partial_file.get_piece_mut(index as usize);
            return match piece.get_offset(begin as usize, offset as usize) {
                Some(piece_data) => {
                    let msg = PeerMsg::Piece(begin, offset, Vec::from(piece_data));
                    Some(msg)
                }
                _ => None,
            };
        }
        None
    }
}
<commit_msg>Simplify keepalive<commit_after>use wire::handler::{PeerId, PeerAction, ServerHandler};
use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;
use file::PartialFile;
use std::collections::HashMap;
use wire::data::PeerMsg;
use std::time::SystemTime;
use file::{PartialFileTrait, PeerFile};

const TIMEOUT_SECONDS: u64 = 60 * 5;
const KEEPALIVE_PERIOD: u64 = 30;

pub struct PeerState {
    has_handshake: bool,
    disconnected: bool,
    peer_choking: bool,
    peer_interested: bool,
    am_choking: bool,
    am_interested: bool,
    last_msg_time: SystemTime,
    last_msg_sent_time: SystemTime,
    file: PeerFile,
}

impl PeerState {
    pub fn new(len: usize) -> PeerState {
        PeerState {
            has_handshake: false,
            disconnected: false,
            peer_choking: true,
            peer_interested: false,
            am_choking: true,
            am_interested: false,
            last_msg_time: SystemTime::now(),
            last_msg_sent_time: SystemTime::now(),
            file: PeerFile::new(len),
        }
    }
}

pub struct PeerServer {
    peers: HashMap<PeerId, PeerState>,
    hash: SHA1Hash20b,
    our_peer_id: String,
    partial_file: PartialFile,
}

const PROTOCOL_ID: &'static str = "rustorrent-beta";

impl ServerHandler for PeerServer {
    fn new(metainfo: MetaInfo, hash: SHA1Hash20b, our_peer_id: &str) -> Self {
        let partial_file = PartialFile::new(&metainfo.info);

        PeerServer {
            peers: HashMap::new(),
            hash: hash,
            our_peer_id: our_peer_id.to_string(),
            partial_file: partial_file,
        }
    }

    fn on_peer_connect(&mut self, id: PeerId) -> PeerAction {
        let handshake = PeerMsg::handshake(PROTOCOL_ID.to_string(),
                                           self.our_peer_id.to_string(),
                                           &self.hash);
        PeerAction::SendMessages(vec![handshake])
    }

    fn on_message_receive(&mut self, id: PeerId, msg: PeerMsg) -> PeerAction {
        {
            let peer = match self.peers.get_mut(&id) {
                Some(peer) => peer,
                None => return PeerAction::Nothing,
            };

            if peer.disconnected {
                return PeerAction::Nothing;
            }

            peer.last_msg_time = SystemTime::now();

            if !peer.has_handshake {
                match msg {
                    PeerMsg::HandShake(_, ref their_hash, _) => {
                        if their_hash == &self.hash {
                            peer.has_handshake = true;
                        } else {
                            peer.disconnected = true;
                            return PeerAction::Disconnect;
                        }
                    }
                    _ => {
                        peer.disconnected = true;
                    }
                }
            }
        }

        let mut outgoing_msgs = Vec::new();
        let mut handled = true;

        {
            let peer = match self.peers.get_mut(&id) {
                Some(peer) => peer,
                None => return PeerAction::Nothing,
            };

            // messages that mutate the peer
            match msg {
                PeerMsg::HandShake(..) => {}
                PeerMsg::KeepAlive => {},
                PeerMsg::Choke => {
                    peer.peer_choking = true;
                }
                PeerMsg::Unchoke => {
                    peer.peer_choking = false;
                }
                PeerMsg::Interested => {
                    peer.peer_interested = true;
                }
                PeerMsg::NotInterested => {
                    peer.peer_interested = false;
                }
                PeerMsg::Have(index) => peer.file.set(index as usize, true),
                PeerMsg::Bitfield(_) => {}
                _ => handled = false,
            };
        }

        // messages that don't need to mutate peer
        let choking = {
            match self.peers.get(&id) {
                Some(peer) => peer.am_choking,
                None => return PeerAction::Nothing,
            }
        };

        if !choking && !handled {
            match msg {
                PeerMsg::Request(index, begin, offset) => {
                    let response = self._get_piece_from_req(index as usize, begin, offset);
                    if response.is_some() {
                        outgoing_msgs.push(response.unwrap());
                    }
                }
                PeerMsg::Piece(index, begin, block) => {
                    self.partial_file.add_piece(index as usize, begin as usize, block);
                }
                PeerMsg::Cancel(..) => {}
                PeerMsg::Port(_) => {}
                _ => handled = true,
            }
        }

        if outgoing_msgs.len() > 0 {
            PeerAction::SendMessages(outgoing_msgs)
        } else {
            PeerAction::Nothing
        }
    }

    fn on_peer_disconnect(&mut self, id: PeerId) -> PeerAction {
        self.peers.remove(&id);
        PeerAction::Nothing
    }

    // remove peers that have no replied in five minutes
    fn on_loop(&mut self) -> PeerAction {
        self._remove_old_peers();
        PeerAction::Nothing
    }
}

impl PeerServer {
    fn _remove_old_peers(&mut self) {
        let for_removal = self._get_timeout_ids();

        for id in for_removal {
            self.peers.remove(&id);
        }

    }

    fn _get_timeout_ids(&self) -> Vec<PeerId> {
        let mut for_removal = Vec::new();
        for (&id, peer) in &self.peers {
            match peer.last_msg_time.elapsed() {
                Ok(duration) => {
                    if duration.as_secs() > TIMEOUT_SECONDS {
                        for_removal.push(id);
                    }
                }
                _ => (),
            }
        }
        for_removal
    }

    fn _get_keepalive_ids(&self) -> Vec<PeerId> {
        let mut for_keeping = Vec::new();
        for (&id, peer) in &self.peers {
            match peer.last_msg_time.elapsed() {
                Ok(duration) => {
                    if duration.as_secs() > KEEPALIVE_PERIOD {
                        for_keeping.push(id);
                    }
                }
                _ => (),
            }
        }
        for_keeping
    }

    fn _get_piece_from_req(&mut self, index: usize, begin: u32, offset: u32) -> Option<PeerMsg> {
        if self.partial_file.has_piece(index as usize) {
            let piece = self.partial_file.get_piece_mut(index as usize);
            return match piece.get_offset(begin as usize, offset as usize) {
                Some(piece_data) => {
                    let msg = PeerMsg::Piece(begin, offset, Vec::from(piece_data));
                    Some(msg)
                }
                _ => None,
            };
        }
        None
    }
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_type(&self, input: State<I>) -> ParseResult<types::Type, I> {
            unimplemented!()
        }

        fn parse_binding(&self, input: State<I>)
                        -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
            let pos = input.position.clone();
            self.parser(MnEnv::parse_name)
                .and(self.type_annotation())
                .and(self.expr())
                .map(|((name, typ), value)|
                    Annotated::new( Binding { name: name
                                            , typ: typ
                                            , value: Rc::new(value)
                                            }
                                   , Position::from(pos)
                               ))
                .parse_state(input)
        }

        fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

            let binding_form =
                self.reserved("let")
                    .with(many(self.parens(self.binding())))
                    .and(many(self.expr()))
                    .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                         , body: body });

            choice([ binding_form ])
                .map(Form::Let)
                .parse_state(input)
        }

        fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
            let position = input.position.clone();
            self.env.identifier::<'b>()
                .map(|name| Positional { pos: Position::from(position)
                                       , value: name })
                .parse_state(input)
        }

        fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            self.name()
                .and(many(self.expr()))
                .map(|(name, args)| Form::Call { fun: name, body: args })
                .parse_state(input)
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([ self.def()
                               , self.if_form()
                               , self.lambda()
                               , self.let_form()
                               , self.call()
                               ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_def)
        }

        fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_if)
        }

        fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_let)
        }

        fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_lambda)
        }

        fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_call)
        }

        fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
            self.parser(MnEnv::parse_name)
        }

        fn binding(&'b self)
                  -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
            self.parser(MnEnv::parse_binding)
        }

        fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
            self.parser(MnEnv::parse_type)
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Started on the type annotation parser<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_type(&self, input: State<I>) -> ParseResult<types::Type, I> {
            let primitive =
                choice([ self.reserved("int")
                             .with(value(types::Primitive::Int))
                       , self.reserved("float")
                             .with(value(types::Primitive::Float))
                       , self.reserved("double")
                             .with(value(types::Primitive::Double))
                       , self.reserved("bool")
                             .with(value(types::Primitive::Bool))
                       ])
                       .map(|primitive| types::Type::Prim(primitive));

            choice([ primitive ])
                .parse_state(input)
        }

        fn parse_binding(&self, input: State<I>)
                        -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
            let pos = input.position.clone();
            self.parser(MnEnv::parse_name)
                .and(self.type_annotation())
                .and(self.expr())
                .map(|((name, typ), value)|
                    Annotated::new( Binding { name: name
                                            , typ: typ
                                            , value: Rc::new(value)
                                            }
                                   , Position::from(pos)
                               ))
                .parse_state(input)
        }

        fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

            let binding_form =
                self.reserved("let")
                    .with(many(self.parens(self.binding())))
                    .and(many(self.expr()))
                    .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                         , body: body });

            choice([ binding_form ])
                .map(Form::Let)
                .parse_state(input)
        }

        fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
            let position = input.position.clone();
            self.env.identifier::<'b>()
                .map(|name| Positional { pos: Position::from(position)
                                       , value: name })
                .parse_state(input)
        }

        fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            self.name()
                .and(many(self.expr()))
                .map(|(name, args)| Form::Call { fun: name, body: args })
                .parse_state(input)
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([ self.def()
                               , self.if_form()
                               , self.lambda()
                               , self.let_form()
                               , self.call()
                               ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_def)
        }

        fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_if)
        }

        fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_let)
        }

        fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_lambda)
        }

        fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            self.parser(MnEnv::parse_call)
        }

        fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
            self.parser(MnEnv::parse_name)
        }

        fn binding(&'b self)
                  -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
            self.parser(MnEnv::parse_binding)
        }

        fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
            self.parser(MnEnv::parse_type)
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      , "i8"                , "u8"
                      , "i16"               , "u16"
                      , "i32"               , "u32"         , "f32"
                      , "i64"               , "u64"         , "f64"
                      , "int"               , "uint"        , "float"
                      , "bool"                              , "double"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(io)]
#![feature(plugin)]
#![plugin(phf_macros)]
#![feature(float_from_str_radix)]

extern crate xml;
extern crate phf;
extern crate num;

extern crate uil_shared;

pub mod style;
pub mod markup;
pub mod deps;

pub use self::report::ErrorReporter;
pub use self::report::StdOutErrorReporter;
pub use self::report::EmptyErrorReporter;

mod parsing;
mod report;
<commit_msg>Fixed unused warning.<commit_after>#![feature(io)]
#![feature(plugin)]
#![plugin(phf_macros)]
#![feature(float_from_str_radix)]

extern crate xml;
extern crate phf;
extern crate num;

extern crate uil_shared;

pub mod style;
pub mod markup;
pub mod deps;

pub use self::report::ErrorReporter;
pub use self::report::StdOutErrorReporter;
pub use self::report::EmptyErrorReporter;

mod parsing;
mod report;
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;

mod graph;
use graph::Graph;

#[derive(Debug, Copy, Clone)]
enum Tile<K> {
  Wall,
  Passage,
  Door(K),
  Key(K)
}

type Position = (usize, usize);
type PositionKeys<K> = (Position, Rc<Vec<K>>);
type Labyrinth<K> = HashMap<Position, Tile<K>>;

impl<K: Hash + Eq + Clone + Ord> Graph<PositionKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, ((x, y), keys): PositionKeys<K>) -> Vec<PositionKeys<K>> {
    [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)].into_iter()
    .cloned()
    .filter(|&(x, y)| x > 0 && y > 0)
    .filter_map(|pos| match self.get(&pos) {
      Some(Tile::Passage) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Door(x)) if keys.contains(x) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Key(k)) => {
        Some((pos, {
          let mut keys = (*keys).clone();

          keys.push(k.clone());
          keys.sort();
          keys.dedup();

          Rc::new(keys)
        }))
      },
      _ => None
    })
    .collect()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("18.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_labyrinth(input: &str) -> (Labyrinth<char>, Option<Position>) {
  let labyrinth = input.lines()
    .enumerate()
    .flat_map(|(y, line)| {
      line.chars()
      .enumerate()
      .map(move |(x, c)| (
        (x, y),
        match c {
          '#' => Tile::Wall,
          '@' => Tile::Passage,
          c if c.is_ascii_uppercase() => Tile::Door(c.to_ascii_lowercase()),
          c if c.is_ascii_lowercase() => Tile::Key(c),
          _ => Tile::Passage
        }
      ))
    })
    .collect::<Labyrinth<_>>();

  let entrance = input.lines()
    .enumerate()
    .find_map(|(y, line)| {
      line.chars()
      .position(|c| c == '@')
      .map(|x| (x, y))
    });

  (labyrinth, entrance)
}

fn get_all_keys<K>(labyrinth: &Labyrinth<K>, position: Position, key_count: usize) -> Option<Vec<Position>>
where K: Hash + Eq + Clone + Ord {
  let mut bfs_iter = labyrinth.bfs((position, Rc::new(vec![])));

  bfs_iter
  .find(|(_, keys)| keys.len() == key_count)
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(position, _)| position)
      .collect()
    })
  })
}

fn main() {
  let input = get_input().unwrap();
  let (mut labyrinth, position) = parse_labyrinth(&input);

  let path = get_all_keys(&labyrinth, position.unwrap(), 26);
  println!("Part 1: {}", path.unwrap().len() - 1);

  let (x, y) = position.unwrap();
  labyrinth.insert((x, y), Tile::Wall);
  labyrinth.insert((x - 1, y), Tile::Wall);
  labyrinth.insert((x + 1, y), Tile::Wall);
  labyrinth.insert((x, y - 1), Tile::Wall);
  labyrinth.insert((x, y + 1), Tile::Wall);

  let positions = vec![(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)];
}
<commit_msg>Add naive solution for day 18 part 2<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;
use std::fmt::Debug;

mod graph;
use graph::Graph;

#[derive(Debug, Copy, Clone)]
enum Tile<K> {
  Wall,
  Passage,
  Door(K),
  Key(K)
}

type Position = (usize, usize);
type PositionKeys<K> = (Position, Rc<Vec<K>>);
type PositionsKeys<K> = (Vec<Position>, Rc<Vec<K>>);
type Labyrinth<K> = HashMap<Position, Tile<K>>;

impl<K: Hash + Eq + Clone + Ord> Graph<PositionKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, ((x, y), keys): PositionKeys<K>) -> Vec<PositionKeys<K>> {
    [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)].into_iter()
    .cloned()
    .filter(|&(x, y)| x > 0 && y > 0)
    .filter_map(|pos| match self.get(&pos) {
      Some(Tile::Passage) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Door(x)) if keys.contains(x) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Key(k)) => {
        Some((pos, {
          let mut keys = (*keys).clone();

          keys.push(k.clone());
          keys.sort();
          keys.dedup();

          Rc::new(keys)
        }))
      },
      _ => None
    })
    .collect()
  }
}

impl<K: Hash + Eq + Clone + Ord> Graph<PositionsKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, (positions, keys): PositionsKeys<K>) -> Vec<PositionsKeys<K>> {
    positions.iter().cloned()
    .map(|position| (position, keys.clone()))
    .enumerate()
    .flat_map(|(i, position_keys)| {
      self.get_neighbors(position_keys).into_iter()
      .map(move |x| (i, x))
      .map(|(i, (position, keys))| {
        let mut positions = positions.clone();
        positions[i] = position;

        (positions, keys)
      })
    })
    .collect()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("18.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_labyrinth(input: &str) -> (Labyrinth<char>, Option<Position>) {
  let labyrinth = input.lines()
    .enumerate()
    .flat_map(|(y, line)| {
      line.chars()
      .enumerate()
      .map(move |(x, c)| (
        (x, y),
        match c {
          '#' => Tile::Wall,
          '@' => Tile::Passage,
          c if c.is_ascii_uppercase() => Tile::Door(c.to_ascii_lowercase()),
          c if c.is_ascii_lowercase() => Tile::Key(c),
          _ => Tile::Passage
        }
      ))
    })
    .collect::<Labyrinth<_>>();

  let entrance = input.lines()
    .enumerate()
    .find_map(|(y, line)| {
      line.chars()
      .position(|c| c == '@')
      .map(|x| (x, y))
    });

  (labyrinth, entrance)
}

fn get_all_keys<K>(labyrinth: &Labyrinth<K>, position: Position, key_count: usize) -> Option<Vec<Position>>
where K: Hash + Eq + Clone + Ord {
  let mut bfs_iter = labyrinth.bfs((position, Rc::new(vec![])));

  bfs_iter
  .find(|(_, keys)| keys.len() == key_count)
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(position, _)| position)
      .collect()
    })
  })
}

fn real_get_all_keys<K>(labyrinth: &Labyrinth<K>, positions: Vec<Position>, key_count: usize) -> Option<Vec<Vec<Position>>>
where K: Hash + Eq + Clone + Ord + Debug {
  let mut bfs_iter = labyrinth.bfs((positions, Rc::new(vec![])));

  bfs_iter
  .find(|(_, keys)| {
    if keys.len() > 5 {
      println!("{:?}", keys);
    }
    keys.len() == key_count
  })
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(positions, _)| positions)
      .collect()
    })
  })
}

fn main() {
  let input = get_input().unwrap();
  let (mut labyrinth, position) = parse_labyrinth(&input);

  let path = get_all_keys(&labyrinth, position.unwrap(), 26);
  println!("Part 1: {}", path.unwrap().len() - 1);

  let (x, y) = position.unwrap();
  labyrinth.insert((x, y), Tile::Wall);
  labyrinth.insert((x - 1, y), Tile::Wall);
  labyrinth.insert((x + 1, y), Tile::Wall);
  labyrinth.insert((x, y - 1), Tile::Wall);
  labyrinth.insert((x, y + 1), Tile::Wall);

  let positions = vec![(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)];
  let path = real_get_all_keys(&labyrinth, positions, 26);

  println!("Part 2: {}", path.unwrap().len() - 1);
}
<|endoftext|>


<commit_before>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct SendContact<'c, 'p, 'f, 'l> {
    chat_id: ChatId<'c>,
    phone_number: Cow<'p, str>,
    first_name: Cow<'f, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    last_name: Option<Cow<'l, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_notification: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_to_message_id: Option<Integer>,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}<commit_msg>Added new and setter functions.<commit_after>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct SendContact<'c, 'p, 'f, 'l> {
    chat_id: ChatId<'c>,
    phone_number: Cow<'p, str>,
    first_name: Cow<'f, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    last_name: Option<Cow<'l, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_notification: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_to_message_id: Option<Integer>,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}

impl<'c, 'p, 'f, 'l> Request for SendContact<'c, 'p, 'f, 'l> {
    type Response = Message;
    type RawResponse = Message;

    fn map(raw: Self::RawResponse) -> Self::Response {
        raw
    }

    fn name() -> &'static str {
        "sendContact"
    }
}

impl<'c, 'p, 'f, 'l> SendContact<'c, 'p, 'f, 'l> {
    pub fn new<C, P, F>(chat: C, phone_number: P, first_name: F) -> Self
        where C: Into<ChatId<'c>>,
              P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>
    {
        SendContact {
            chat_id: chat.into(),
            phone_number: phone_number.into(),
            first_name: first_name.into(),
            last_name: None,
            disable_notification: false,
            reply_to_message_id: None,
            reply_markup: None,
        }
    }

    pub fn last_name<F>(mut self, last_name: F) -> Self where F: Into<Cow<'l, str>> {
        self.last_name = Some(last_name.into());
        self
    }

    pub fn disable_notification(mut self) -> Self {
        self.disable_notification = true;
        self
    }

    pub fn reply_to<R>(mut self, to: R) -> Self where R: Into<MessageId> {
        self.reply_to_message_id = Some(to.into().0);
        self
    }

    pub fn reply_markup<R>(mut self, reply_markup: R) -> Self where R: Into<ReplyMarkup> {
        self.reply_markup = Some(reply_markup.into());
        self
    }
}<|endoftext|>


<commit_before>//! Functionality for downloading crates and maintaining download counts
//!
//! Crate level functionality is located in `krate::downloads`.

use crate::controllers::prelude::*;

use chrono::{Duration, NaiveDate, Utc};

use crate::models::{Crate, VersionDownload};
use crate::schema::*;
use crate::views::EncodableVersionDownload;

use super::version_and_crate;

/// Handles the `GET /crates/:crate_id/:version/download` route.
/// This returns a URL to the location where the crate is stored.
pub fn download(req: &mut dyn Request) -> CargoResult<Response> {
    let crate_name = &req.params()["crate_id"];
    let version = &req.params()["version"];

    increment_download_counts(req, crate_name, version)?;

    let redirect_url = req
        .app()
        .config
        .uploader
        .crate_location(crate_name, version)
        .ok_or_else(|| human("crate files not found"))?;

    if req.wants_json() {
        #[derive(Serialize)]
        struct R {
            url: String,
        }
        Ok(req.json(&R { url: redirect_url }))
    } else {
        Ok(req.redirect(redirect_url))
    }
}

/// Increment the download counts for a given crate version.
///
/// Returns an error if we could not load the version ID from the database.
///
/// This ignores any errors that occur updating the download count. Failure is
/// expected if the application is in read only mode, or for API-only mirrors.
/// Even if failure occurs for unexpected reasons, we would rather have `cargo
/// build` succeed and not count the download than break people's builds.
fn increment_download_counts(
    req: &dyn Request,
    crate_name: &str,
    version: &str,
) -> CargoResult<()> {
    use self::versions::dsl::*;

    let conn = req.db_conn()?;
    let version_id = versions
        .select(id)
        .filter(crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)))
        .filter(num.eq(version))
        .first(&*conn)?;

    // Wrap in a transaction so we don't poison the outer transaction if this
    // fails
    let _ = conn.transaction(|| {
        VersionDownload::create_or_increment(version_id, &conn)
    });
    Ok(())
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut dyn Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let cutoff_end_date = req
        .query()
        .get("before_date")
        .and_then(|d| NaiveDate::parse_from_str(d, "%F").ok())
        .unwrap_or_else(|| Utc::today().naive_utc());
    let cutoff_start_date = cutoff_end_date - Duration::days(89);

    let downloads = VersionDownload::belonging_to(&version)
        .filter(version_downloads::date.between(cutoff_start_date, cutoff_end_date))
        .order(version_downloads::date)
        .load(&*conn)?
        .into_iter()
        .map(VersionDownload::encodable)
        .collect();

    #[derive(Serialize)]
    struct R {
        version_downloads: Vec<EncodableVersionDownload>,
    }
    Ok(req.json(&R {
        version_downloads: downloads,
    }))
}
<commit_msg>rustfmt<commit_after>//! Functionality for downloading crates and maintaining download counts
//!
//! Crate level functionality is located in `krate::downloads`.

use crate::controllers::prelude::*;

use chrono::{Duration, NaiveDate, Utc};

use crate::models::{Crate, VersionDownload};
use crate::schema::*;
use crate::views::EncodableVersionDownload;

use super::version_and_crate;

/// Handles the `GET /crates/:crate_id/:version/download` route.
/// This returns a URL to the location where the crate is stored.
pub fn download(req: &mut dyn Request) -> CargoResult<Response> {
    let crate_name = &req.params()["crate_id"];
    let version = &req.params()["version"];

    increment_download_counts(req, crate_name, version)?;

    let redirect_url = req
        .app()
        .config
        .uploader
        .crate_location(crate_name, version)
        .ok_or_else(|| human("crate files not found"))?;

    if req.wants_json() {
        #[derive(Serialize)]
        struct R {
            url: String,
        }
        Ok(req.json(&R { url: redirect_url }))
    } else {
        Ok(req.redirect(redirect_url))
    }
}

/// Increment the download counts for a given crate version.
///
/// Returns an error if we could not load the version ID from the database.
///
/// This ignores any errors that occur updating the download count. Failure is
/// expected if the application is in read only mode, or for API-only mirrors.
/// Even if failure occurs for unexpected reasons, we would rather have `cargo
/// build` succeed and not count the download than break people's builds.
fn increment_download_counts(
    req: &dyn Request,
    crate_name: &str,
    version: &str,
) -> CargoResult<()> {
    use self::versions::dsl::*;

    let conn = req.db_conn()?;
    let version_id = versions
        .select(id)
        .filter(crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)))
        .filter(num.eq(version))
        .first(&*conn)?;

    // Wrap in a transaction so we don't poison the outer transaction if this
    // fails
    let _ = conn.transaction(|| VersionDownload::create_or_increment(version_id, &conn));
    Ok(())
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut dyn Request) -> CargoResult<Response> {
    let (version, _) = version_and_crate(req)?;
    let conn = req.db_conn()?;
    let cutoff_end_date = req
        .query()
        .get("before_date")
        .and_then(|d| NaiveDate::parse_from_str(d, "%F").ok())
        .unwrap_or_else(|| Utc::today().naive_utc());
    let cutoff_start_date = cutoff_end_date - Duration::days(89);

    let downloads = VersionDownload::belonging_to(&version)
        .filter(version_downloads::date.between(cutoff_start_date, cutoff_end_date))
        .order(version_downloads::date)
        .load(&*conn)?
        .into_iter()
        .map(VersionDownload::encodable)
        .collect();

    #[derive(Serialize)]
    struct R {
        version_downloads: Vec<EncodableVersionDownload>,
    }
    Ok(req.json(&R {
        version_downloads: downloads,
    }))
}
<|endoftext|>


<commit_before>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::layout::LayoutOf;
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    InterpResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

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

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references must in fact be immutable due to their surrounding immutability in a
    /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mtu`
    /// that will actually be treated as mutable.
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'a, 'mir, 'tcx> InternVisitor<'rt, 'a, 'mir, 'tcx> {
    fn intern(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'a, 'mir, 'tcx>
    ValueVisitor<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
for
    InternVisitor<'rt, 'a, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'a, 'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
    ) -> InterpResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, _, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                let layout = self.ecx.layout_of(ty.builtin_deref(true).unwrap().ty)?;
                if layout.is_unsized() {
                    if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(layout.ty).sty {
                        if let Ok(vtable) = meta.unwrap().to_ptr() {
                            // explitly choose `Immutable` here, since vtables are immutable, even
                            // if the reference of the fat pointer is mutable
                            self.intern(vtable, Mutability::Immutable)?;
                        }
                    }
                }
            }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // In the future we will probably allow `& &mut T`, and thus will want to merge
                // `mutability` with `self.mutability` to only choose `Mutable` if both are
                // `Mutable`.

                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                // This is not an inherent limitation, but one that we know to be true, because
                // const qualification enforces it. We can lift it in the future.
                match (self.mode, mutability) {
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // all is "good and well" in the unsoundness of `static mut`

                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) =>
                        bug!("const qualif failed to prevent mutable references"),
                }
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx> {
    let tcx = ecx.tcx;
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<commit_msg>s/intern/intern_shallow/<commit_after>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::layout::LayoutOf;
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    InterpResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

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

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references must in fact be immutable due to their surrounding immutability in a
    /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mtu`
    /// that will actually be treated as mutable.
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'a, 'mir, 'tcx> InternVisitor<'rt, 'a, 'mir, 'tcx> {
    /// Intern an allocation without looking at its children
    fn intern_shallow(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'a, 'mir, 'tcx>
    ValueVisitor<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
for
    InternVisitor<'rt, 'a, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'a, 'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
    ) -> InterpResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, _, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                let layout = self.ecx.layout_of(ty.builtin_deref(true).unwrap().ty)?;
                if layout.is_unsized() {
                    if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(layout.ty).sty {
                        if let Ok(vtable) = meta.unwrap().to_ptr() {
                            // explitly choose `Immutable` here, since vtables are immutable, even
                            // if the reference of the fat pointer is mutable
                            self.intern_shallow(vtable, Mutability::Immutable)?;
                        }
                    }
                }
            }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // In the future we will probably allow `& &mut T`, and thus will want to merge
                // `mutability` with `self.mutability` to only choose `Mutable` if both are
                // `Mutable`.

                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                // This is not an inherent limitation, but one that we know to be true, because
                // const qualification enforces it. We can lift it in the future.
                match (self.mode, mutability) {
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // all is "good and well" in the unsoundness of `static mut`

                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) =>
                        bug!("const qualif failed to prevent mutable references"),
                }
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern_shallow(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx> {
    let tcx = ecx.tcx;
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<|endoftext|>