<commit_before>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use rustc_hash::FxHashMap;

use crate::{
    HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait,
    ids::TraitId,
    impl_block::{ImplId, ImplBlock, ImplItem},
    ty::{AdtDef, Ty},
};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Adt(AdtDef), // we'll also want to index impls for primitive types etc.
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Adt { def_id, .. } => Some(TyFingerprint::Adt(*def_id)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the ModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(
        &'a self,
        db: &'a impl HirDatabase,
        ty: &Ty,
    ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                let module_impl_blocks = db.impls_in_module(module);
                (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        db: &'a impl HirDatabase,
        tr: &Trait,
    ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
        let id = tr.id;
        self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                let module_impl_blocks = db.impls_in_module(module);
                (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
        let module_impl_blocks = db.impls_in_module(module.clone());

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);

            let target_ty = impl_block.target_ty(db);

            if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                self.impls
                    .entry(target_ty_fp)
                    .or_insert_with(Vec::new)
                    .push((module.module_id, impl_id));
            }

            if let Some(tr) = impl_block.target_trait(db) {
                self.impls_by_trait
                    .entry(tr.id)
                    .or_insert_with(Vec::new)
                    .push((module.module_id, impl_id));
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, &child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, &module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
    match ty {
        Ty::Adt { def_id, .. } => def_id.krate(db),
        _ => None,
    }
}

impl Ty {
    // TODO: cache this as a query?
    // - if so, what signature? (TyFingerprint, Name)?
    // - or maybe cache all names and def_ids of methods per fingerprint?
    pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> {
        self.iterate_methods(db, |f| {
            let sig = f.signature(db);
            if sig.name() == name && sig.has_self_param() {
                Some(f)
            } else {
                None
            }
        })
    }

    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_methods<T>(
        self,
        db: &impl HirDatabase,
        mut callback: impl FnMut(Function) -> Option<T>,
    ) -> Option<T> {
        // For method calls, rust first does any number of autoderef, and then one
        // autoref (i.e. when the method takes &self or &mut self). We just ignore
        // the autoref currently -- when we find a method matching the given name,
        // we assume it fits.

        // Also note that when we've got a receiver like &S, even if the method we
        // find in the end takes &self, we still do the autoderef step (just as
        // rustc does an autoderef and then autoref again).

        for derefed_ty in self.autoderef(db) {
            let krate = match def_crate(db, &derefed_ty) {
                Some(krate) => krate,
                None => continue,
            };
            let impls = db.impls_in_crate(krate);

            for (_, impl_block) in impls.lookup_impl_blocks(db, &derefed_ty) {
                for item in impl_block.items() {
                    match item {
                        ImplItem::Method(f) => {
                            if let Some(result) = callback(f.clone()) {
                                return Some(result);
                            }
                        }
                        _ => {}
                    }
                }
            }
        }
        None
    }
}
<commit_msg>replace clone with copy<commit_after>//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
use std::sync::Arc;

use rustc_hash::FxHashMap;

use crate::{
    HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait,
    ids::TraitId,
    impl_block::{ImplId, ImplBlock, ImplItem},
    ty::{AdtDef, Ty},
};

/// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint {
    Adt(AdtDef), // we'll also want to index impls for primitive types etc.
}

impl TyFingerprint {
    /// Creates a TyFingerprint for looking up an impl. Only certain types can
    /// have impls: if we have some `struct S`, we can have an `impl S`, but not
    /// `impl &S`. Hence, this will return `None` for reference types and such.
    fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
        match ty {
            Ty::Adt { def_id, .. } => Some(TyFingerprint::Adt(*def_id)),
            _ => None,
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct CrateImplBlocks {
    /// To make sense of the ModuleIds, we need the source root.
    krate: Crate,
    impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>,
    impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>,
}

impl CrateImplBlocks {
    pub fn lookup_impl_blocks<'a>(
        &'a self,
        db: &'a impl HirDatabase,
        ty: &Ty,
    ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
        let fingerprint = TyFingerprint::for_impl(ty);
        fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                let module_impl_blocks = db.impls_in_module(module);
                (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
            },
        )
    }

    pub fn lookup_impl_blocks_for_trait<'a>(
        &'a self,
        db: &'a impl HirDatabase,
        tr: &Trait,
    ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
        let id = tr.id;
        self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
            move |(module_id, impl_id)| {
                let module = Module { krate: self.krate, module_id: *module_id };
                let module_impl_blocks = db.impls_in_module(module);
                (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
            },
        )
    }

    fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
        let module_impl_blocks = db.impls_in_module(module.clone());

        for (impl_id, _) in module_impl_blocks.impls.iter() {
            let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);

            let target_ty = impl_block.target_ty(db);

            if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
                self.impls
                    .entry(target_ty_fp)
                    .or_insert_with(Vec::new)
                    .push((module.module_id, impl_id));
            }

            if let Some(tr) = impl_block.target_trait(db) {
                self.impls_by_trait
                    .entry(tr.id)
                    .or_insert_with(Vec::new)
                    .push((module.module_id, impl_id));
            }
        }

        for child in module.children(db) {
            self.collect_recursive(db, &child);
        }
    }

    pub(crate) fn impls_in_crate_query(
        db: &impl HirDatabase,
        krate: Crate,
    ) -> Arc<CrateImplBlocks> {
        let mut crate_impl_blocks = CrateImplBlocks {
            krate,
            impls: FxHashMap::default(),
            impls_by_trait: FxHashMap::default(),
        };
        if let Some(module) = krate.root_module(db) {
            crate_impl_blocks.collect_recursive(db, &module);
        }
        Arc::new(crate_impl_blocks)
    }
}

fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
    match ty {
        Ty::Adt { def_id, .. } => def_id.krate(db),
        _ => None,
    }
}

impl Ty {
    // TODO: cache this as a query?
    // - if so, what signature? (TyFingerprint, Name)?
    // - or maybe cache all names and def_ids of methods per fingerprint?
    pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> {
        self.iterate_methods(db, |f| {
            let sig = f.signature(db);
            if sig.name() == name && sig.has_self_param() {
                Some(f)
            } else {
                None
            }
        })
    }

    // This would be nicer if it just returned an iterator, but that runs into
    // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
    pub fn iterate_methods<T>(
        self,
        db: &impl HirDatabase,
        mut callback: impl FnMut(Function) -> Option<T>,
    ) -> Option<T> {
        // For method calls, rust first does any number of autoderef, and then one
        // autoref (i.e. when the method takes &self or &mut self). We just ignore
        // the autoref currently -- when we find a method matching the given name,
        // we assume it fits.

        // Also note that when we've got a receiver like &S, even if the method we
        // find in the end takes &self, we still do the autoderef step (just as
        // rustc does an autoderef and then autoref again).

        for derefed_ty in self.autoderef(db) {
            let krate = match def_crate(db, &derefed_ty) {
                Some(krate) => krate,
                None => continue,
            };
            let impls = db.impls_in_crate(krate);

            for (_, impl_block) in impls.lookup_impl_blocks(db, &derefed_ty) {
                for item in impl_block.items() {
                    match item {
                        ImplItem::Method(f) => {
                            if let Some(result) = callback(*f) {
                                return Some(result);
                            }
                        }
                        _ => {}
                    }
                }
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>use ruma_identifiers::RoomVersionId;

use crate::{Error, Result};

#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum RoomDisposition {
    /// A room version that has a stable specification.
    Stable,
    /// A room version that is not yet fully specified.
    Unstable,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum EventFormatVersion {
    /// $id:server event id format
    V1,
    /// MSC1659-style $hash event id format: introduced for room v3
    V2,
    /// MSC1884-style $hash format: introduced for room v4
    V3,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum StateResolutionVersion {
    /// State resolution for rooms at version 1.
    V1,
    /// State resolution for room at version 2 or later.
    V2,
}

#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomVersion {
    /// The stability of this room.
    pub disposition: RoomDisposition,
    /// The format of the EventId.
    pub event_format: EventFormatVersion,
    /// Which state resolution algorithm is used.
    pub state_res: StateResolutionVersion,
    // FIXME: not sure what this one means?
    pub enforce_key_validity: bool,

    /// `m.room.aliases` had special auth rules and redaction rules
    /// before room version 6.
    ///
    /// before MSC2261/MSC2432,
    pub special_case_aliases_auth: bool,
    /// Strictly enforce canonical json, do not allow:
    /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1]
    /// * Floats
    /// * NaN, Infinity, -Infinity
    pub strict_canonicaljson: bool,
    /// Verify notifications key while checking m.room.power_levels.
    ///
    /// bool: MSC2209: Check 'notifications'
    pub limit_notifications_power_levels: bool,
    /// Extra rules when verifying redaction events.
    pub extra_redaction_checks: bool,
    /// Allow knocking in event authentication.
    ///
    /// See: https://spec.matrix.org/unstable/rooms/v7/ for more information.
    pub allow_knocking: bool,
    /// Adds support for the restricted join rule.
    ///
    /// See: https://github.com/matrix-org/matrix-doc/pull/3289 for more information.
    pub restricted_join_rules: bool,
}

impl RoomVersion {
    pub const V1: Self = Self {
        disposition: RoomDisposition::Stable,
        event_format: EventFormatVersion::V1,
        state_res: StateResolutionVersion::V1,
        enforce_key_validity: false,
        special_case_aliases_auth: true,
        strict_canonicaljson: false,
        limit_notifications_power_levels: false,
        extra_redaction_checks: false,
        allow_knocking: false,
        restricted_join_rules: false,
    };

    pub const V2: Self = Self { state_res: StateResolutionVersion::V2, ..Self::V1 };

    pub const V3: Self =
        Self { event_format: EventFormatVersion::V2, extra_redaction_checks: true, ..Self::V2 };

    pub const V4: Self = Self { event_format: EventFormatVersion::V3, ..Self::V3 };

    pub const V5: Self = Self { enforce_key_validity: true, ..Self::V4 };

    pub const V6: Self = Self {
        special_case_aliases_auth: false,
        strict_canonicaljson: true,
        limit_notifications_power_levels: true,
        ..Self::V5
    };

    pub const V7: Self = Self {
        // FIXME: once room version 7 is stabilized move this to version 8
        disposition: RoomDisposition::Unstable,
        allow_knocking: true,
        ..Self::V6
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const V8: Self = Self { restricted_join_rules: true, ..Self::V7 };

    #[cfg(feature = "unstable-pre-spec")]
    pub const V9: Self = Self::V8;

    pub fn new(version: &RoomVersionId) -> Result<Self> {
        Ok(match version {
            RoomVersionId::V1 => Self::V1,
            RoomVersionId::V2 => Self::V2,
            RoomVersionId::V3 => Self::V3,
            RoomVersionId::V4 => Self::V4,
            RoomVersionId::V5 => Self::V5,
            RoomVersionId::V6 => Self::V6,
            RoomVersionId::V7 => Self::V7,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V8 => Self::V8,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V9 => Self::V9,
            ver => return Err(Error::Unsupported(format!("found version `{}`", ver.as_str()))),
        })
    }
}
<commit_msg>state-res: Update spec link and linkify links<commit_after>use ruma_identifiers::RoomVersionId;

use crate::{Error, Result};

#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum RoomDisposition {
    /// A room version that has a stable specification.
    Stable,
    /// A room version that is not yet fully specified.
    Unstable,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum EventFormatVersion {
    /// $id:server event id format
    V1,
    /// MSC1659-style $hash event id format: introduced for room v3
    V2,
    /// MSC1884-style $hash format: introduced for room v4
    V3,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum StateResolutionVersion {
    /// State resolution for rooms at version 1.
    V1,
    /// State resolution for room at version 2 or later.
    V2,
}

#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomVersion {
    /// The stability of this room.
    pub disposition: RoomDisposition,
    /// The format of the EventId.
    pub event_format: EventFormatVersion,
    /// Which state resolution algorithm is used.
    pub state_res: StateResolutionVersion,
    // FIXME: not sure what this one means?
    pub enforce_key_validity: bool,

    /// `m.room.aliases` had special auth rules and redaction rules
    /// before room version 6.
    ///
    /// before MSC2261/MSC2432,
    pub special_case_aliases_auth: bool,
    /// Strictly enforce canonical json, do not allow:
    /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1]
    /// * Floats
    /// * NaN, Infinity, -Infinity
    pub strict_canonicaljson: bool,
    /// Verify notifications key while checking m.room.power_levels.
    ///
    /// bool: MSC2209: Check 'notifications'
    pub limit_notifications_power_levels: bool,
    /// Extra rules when verifying redaction events.
    pub extra_redaction_checks: bool,
    /// Allow knocking in event authentication.
    ///
    /// See: <https://spec.matrix.org/v1.1/rooms/v7/> for more information.
    pub allow_knocking: bool,
    /// Adds support for the restricted join rule.
    ///
    /// See: <https://github.com/matrix-org/matrix-doc/pull/3289> for more information.
    pub restricted_join_rules: bool,
}

impl RoomVersion {
    pub const V1: Self = Self {
        disposition: RoomDisposition::Stable,
        event_format: EventFormatVersion::V1,
        state_res: StateResolutionVersion::V1,
        enforce_key_validity: false,
        special_case_aliases_auth: true,
        strict_canonicaljson: false,
        limit_notifications_power_levels: false,
        extra_redaction_checks: false,
        allow_knocking: false,
        restricted_join_rules: false,
    };

    pub const V2: Self = Self { state_res: StateResolutionVersion::V2, ..Self::V1 };

    pub const V3: Self =
        Self { event_format: EventFormatVersion::V2, extra_redaction_checks: true, ..Self::V2 };

    pub const V4: Self = Self { event_format: EventFormatVersion::V3, ..Self::V3 };

    pub const V5: Self = Self { enforce_key_validity: true, ..Self::V4 };

    pub const V6: Self = Self {
        special_case_aliases_auth: false,
        strict_canonicaljson: true,
        limit_notifications_power_levels: true,
        ..Self::V5
    };

    pub const V7: Self = Self {
        // FIXME: once room version 7 is stabilized move this to version 8
        disposition: RoomDisposition::Unstable,
        allow_knocking: true,
        ..Self::V6
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const V8: Self = Self { restricted_join_rules: true, ..Self::V7 };

    #[cfg(feature = "unstable-pre-spec")]
    pub const V9: Self = Self::V8;

    pub fn new(version: &RoomVersionId) -> Result<Self> {
        Ok(match version {
            RoomVersionId::V1 => Self::V1,
            RoomVersionId::V2 => Self::V2,
            RoomVersionId::V3 => Self::V3,
            RoomVersionId::V4 => Self::V4,
            RoomVersionId::V5 => Self::V5,
            RoomVersionId::V6 => Self::V6,
            RoomVersionId::V7 => Self::V7,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V8 => Self::V8,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V9 => Self::V9,
            ver => return Err(Error::Unsupported(format!("found version `{}`", ver.as_str()))),
        })
    }
}
<|endoftext|>


<commit_before>use common::communicate::{ClientToServer, ServerToClient, TerrainBlockSend, spark_socket_sender};
use common::process_events::process_channel;
use gaia_thread::{ServerToGaia, LoadReason};
use nanomsg::Endpoint;
use server::Server;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::Mutex;
use time;

pub fn client_thread(
  client_endpoints: &mut Vec<Endpoint>,
  server: &Server,
  ups_from_client: &Receiver<ClientToServer>,
  ups_to_gaia: &Mutex<Sender<ServerToGaia>>,
) {
  // TODO: Proper exit semantics for this and other threads.
  loop {
    let update = ups_from_client.recv().unwrap();
    match update {
      ClientToServer::Init(client_url) => {
        let (client, endpoint) = spark_socket_sender(client_url);
        client_endpoints.push(endpoint);
        let player_position = server.player.lock().unwrap().position;
        server.to_client.lock().unwrap().as_mut().map(|client| {
          client.send(ServerToClient::UpdatePlayer(player_position)).unwrap();
        });
        server.inform_client(&client);
        *server.to_client.lock().unwrap() = Some(client);
      },
      ClientToServer::StartJump => {
        let mut player = server.player.lock().unwrap();
        if !player.is_jumping {
          player.is_jumping = true;
          // this 0.3 is duplicated in a few places
          player.accel.y = player.accel.y + 0.3;
        }
      },
      ClientToServer::StopJump => {
        let mut player = server.player.lock().unwrap();
        if player.is_jumping {
          player.is_jumping = false;
          // this 0.3 is duplicated in a few places
          player.accel.y = player.accel.y - 0.3;
        }
      },
      ClientToServer::Walk(v) => {
        let mut player = server.player.lock().unwrap();
        player.walk(v);
      },
      ClientToServer::RotatePlayer(v) => {
        let mut player = server.player.lock().unwrap();
        player.rotate_lateral(v.x);
        player.rotate_vertical(v.y);
      },
      ClientToServer::RequestBlock(position, lod) => {
        ups_to_gaia.lock().unwrap().send(
          ServerToGaia::Load(position, lod, LoadReason::ForClient)
        ).unwrap();
      },
    };
  }
}
<commit_msg>Remove unused imports.<commit_after>use common::communicate::{ClientToServer, ServerToClient, spark_socket_sender};
use gaia_thread::{ServerToGaia, LoadReason};
use nanomsg::Endpoint;
use server::Server;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::Mutex;

pub fn client_thread(
  client_endpoints: &mut Vec<Endpoint>,
  server: &Server,
  ups_from_client: &Receiver<ClientToServer>,
  ups_to_gaia: &Mutex<Sender<ServerToGaia>>,
) {
  // TODO: Proper exit semantics for this and other threads.
  loop {
    let update = ups_from_client.recv().unwrap();
    match update {
      ClientToServer::Init(client_url) => {
        let (client, endpoint) = spark_socket_sender(client_url);
        client_endpoints.push(endpoint);
        let player_position = server.player.lock().unwrap().position;
        server.to_client.lock().unwrap().as_mut().map(|client| {
          client.send(ServerToClient::UpdatePlayer(player_position)).unwrap();
        });
        server.inform_client(&client);
        *server.to_client.lock().unwrap() = Some(client);
      },
      ClientToServer::StartJump => {
        let mut player = server.player.lock().unwrap();
        if !player.is_jumping {
          player.is_jumping = true;
          // this 0.3 is duplicated in a few places
          player.accel.y = player.accel.y + 0.3;
        }
      },
      ClientToServer::StopJump => {
        let mut player = server.player.lock().unwrap();
        if player.is_jumping {
          player.is_jumping = false;
          // this 0.3 is duplicated in a few places
          player.accel.y = player.accel.y - 0.3;
        }
      },
      ClientToServer::Walk(v) => {
        let mut player = server.player.lock().unwrap();
        player.walk(v);
      },
      ClientToServer::RotatePlayer(v) => {
        let mut player = server.player.lock().unwrap();
        player.rotate_lateral(v.x);
        player.rotate_vertical(v.y);
      },
      ClientToServer::RequestBlock(position, lod) => {
        ups_to_gaia.lock().unwrap().send(
          ServerToGaia::Load(position, lod, LoadReason::ForClient)
        ).unwrap();
      },
    };
  }
}
<|endoftext|>


<commit_before>use std::io::{IoError, OtherIoError};
use std::io::{File, Open, Write};
use std::io::{BufferedReader, MemWriter};
use std::cmp::min;
use std::from_str::FromStr;
use std::io::process::{ExitStatus, ExitSignal, Command, Ignored, InheritFd};

use libc::funcs::posix88::unistd::{geteuid, getegid};
use libc::{pid_t, uid_t, gid_t};

use config::Range;
use config::Settings;
use super::util::get_user_name;

#[deriving(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map() -> Result<Vec<Range>,String> {
    let uid = unsafe { geteuid() };
    let user = try!(get_user_name(uid)
        .map_err(|e| format!("Error getting user name for {}: {}", uid, e)));
    let file = File::open(&Path::new("/etc/subuid"));
    let mut res = Vec::new();
    let mut reader = BufferedReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try!(line.map_err(
            |e| format!("Error reading /etc/subuid: {}", e)));
        let parts: Vec<&str> = line.as_slice().split(':').collect();
        let start = from_str(parts[1]);
        let count = from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_none() || count.is_none() {
            return Err(format!("/etc/subuid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(&user.as_slice()) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

fn read_gid_map() -> Result<Vec<Range>,String> {
    let uid = unsafe { geteuid() };
    let user = try!(get_user_name(uid)
        .map_err(|e| format!("Error getting user name for {}: {}", uid, e)));
    let file = File::open(&Path::new("/etc/subgid"));
    let mut res = Vec::new();
    let mut reader = BufferedReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try!(line.map_err(
            |e| format!("Error reading /etc/subgid: {}", e)));
        let parts: Vec<&str> = line.as_slice().split(':').collect();
        let start = from_str(parts[1]);
        let count = from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_none() || count.is_none() {
            return Err(format!("/etc/subgid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(&user.as_slice()) {
            let start: gid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Vec<(uid_t, uid_t, uid_t)>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start, allowval.start, clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => unreachable!(),
            };
        }
    }
    return res;
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let uid_map = read_uid_map().ok();
    let gid_map = read_gid_map().ok();

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Some(uid_map), Some(gid_map)) = (uid_map, gid_map) {
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start && uid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start, rng.start, rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start && gid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start, rng.start, rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!(concat!("Your system doesn't have /etc/subuid and /etc/subgid.",
            " Presumably your system is too old. Some features may not work"));
        return Ok(Singleton(uid, gid));
    }
}

pub fn apply_uidmap(pid: pid_t, map: &Uidmap) -> Result<(), IoError> {
    match map {
        &Singleton(uid, gid) => {
            let uid_map = format!("0 {} 1", uid);
            debug!("Writing uid_map: {}", uid_map);
            match File::open_mode(&Path::new("/proc")
                              .join(pid.to_string())
                              .join("uid_map"), Open, Write)
                    .write_str(uid_map.as_slice()) {
                Ok(()) => {}
                Err(e) => return Err(IoError {
                    kind: e.kind,
                    desc: "Error writing uid mapping",
                    detail: e.detail,
                    }),
            }
            let gid_map = format!("0 {} 1", gid);
            debug!("Writing gid_map: {}", gid_map);
            match File::open_mode(&Path::new("/proc")
                              .join(pid.to_string())
                              .join("gid_map"), Open, Write)
                    .write_str(uid_map.as_slice()) {
                Ok(()) => {}
                Err(e) => return Err(IoError {
                    kind: e.kind,
                    desc: "Error writing gid mapping",
                    detail: e.detail
                    }),
            }
        }
        &Ranges(ref uids, ref gids) => {
            let myuid = unsafe { geteuid() };
            if myuid > 0 {
                let mut cmd = Command::new("newuidmap");
                cmd.stdin(Ignored).stdout(InheritFd(1)).stderr(InheritFd(2));
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in uids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Uid map command: {}", cmd);
                match cmd.status() {
                    Ok(ExitStatus(0)) => {},
                    Ok(ExitStatus(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing uid mapping",
                            detail: Some(format!(
                                "newuidmap exited with status {}", x)),
                            });
                    }
                    Ok(ExitSignal(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing uid mapping",
                            detail: Some(format!(
                                "newuidmap exited with signal {}", x)),
                            });
                    }
                    Err(e) => return Err(IoError {
                        kind: e.kind,
                        desc: "Error writing uid mapping",
                        detail: e.detail
                        }),
                }

                let mut cmd = Command::new("newgidmap");
                cmd.stdin(Ignored).stdout(InheritFd(1)).stderr(InheritFd(2));
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in gids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Gid map command: {}", cmd);
                match cmd.status() {
                    Ok(ExitStatus(0)) => {},
                    Ok(ExitStatus(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing gid mapping",
                            detail: Some(format!(
                                "newgidmap exited with status {}", x)),
                            });
                    }
                    Ok(ExitSignal(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing gid mapping",
                            detail: Some(format!(
                                "newgidmap exited with signal {}", x)),
                            });
                    }
                    Err(e) => return Err(IoError {
                        kind: e.kind,
                        desc: "Error writing gid mapping",
                        detail: e.detail
                        }),
                }
            } else {
                let mut membuf = MemWriter::new();
                for &(ins, outs, cnt) in uids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/uid_map", pid))));
                let value = membuf.unwrap();
                debug!("Writing uid map ```{}```",
                    String::from_utf8_lossy(value.as_slice()));
                try!(file.write(value.as_slice()));

                let mut membuf = MemWriter::new();
                for &(ins, outs, cnt) in gids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/gid_map", pid))));
                let value = membuf.unwrap();
                debug!("Writing gid map ```{}```",
                    String::from_utf8_lossy(value.as_slice()));
                try!(file.write(value.as_slice()));
            }
        }
    }
    return Ok(());
}

fn read_outside_ranges(path: &str) -> Result<Vec<Range>, String> {
    let mut file = BufferedReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|e| format!("Error reading uid/gid map: {}", e)));
        let mut words = line.as_slice().words();
        let outside = try!(words.next().and_then(FromStr::from_str)
            .ok_or(format!("uid/gid map format error")));
        try!(words.next()
            .ok_or(format!("uid/gid map format error")));
        let count = try!(words.next().and_then(FromStr::from_str)
            .ok_or(format!("uid/gid map format error")));
        result.push(Range { start: outside, end: outside+count-1 });
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range { start: 0, end: 0 });
    let default_gids = vec!(Range { start: 0, end: 0 });
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    if settings.uid_map.is_none() {
        let ranges = try!(read_outside_ranges("/proc/self/uid_map"));
        let uid_map = match_ranges(uids, &ranges, 0);
        let ranges = try!(read_outside_ranges("/proc/self/gid_map"));
        let gid_map = match_ranges(gids, &ranges, 0);
        return Ok(Ranges(uid_map, gid_map));
    } else {
        let &(ref uids, ref gids) = settings.uid_map.as_ref().unwrap();
        return Ok(Ranges(uids.clone(), gids.clone()));
    }
}
<commit_msg>Use `id` command instead of `getpwuid`<commit_after>use std::os::getenv;
use std::io::{IoError, OtherIoError};
use std::io::{File, Open, Write};
use std::io::{BufferedReader, MemWriter};
use std::cmp::min;
use std::from_str::FromStr;
use std::str::from_utf8;
use std::io::process::{ExitStatus, ExitSignal, Command, Ignored, InheritFd};

use libc::funcs::posix88::unistd::{geteuid, getegid};
use libc::{pid_t, uid_t, gid_t};

use config::Range;
use config::Settings;

#[deriving(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = File::open(&Path::new("/etc/subuid"));
    let mut res = Vec::new();
    let mut reader = BufferedReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try!(line.map_err(
            |e| format!("Error reading /etc/subuid: {}", e)));
        let parts: Vec<&str> = line.as_slice().split(':').collect();
        let start = from_str(parts[1]);
        let count = from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_none() || count.is_none() {
            return Err(format!("/etc/subuid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(&username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

fn read_gid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = File::open(&Path::new("/etc/subgid"));
    let mut res = Vec::new();
    let mut reader = BufferedReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try!(line.map_err(
            |e| format!("Error reading /etc/subgid: {}", e)));
        let parts: Vec<&str> = line.as_slice().split(':').collect();
        let start = from_str(parts[1]);
        let count = from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_none() || count.is_none() {
            return Err(format!("/etc/subgid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(&username) {
            let start: gid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Vec<(uid_t, uid_t, uid_t)>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start, allowval.start, clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => unreachable!(),
            };
        }
    }
    return res;
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let mut cmd = Command::new("id");
    cmd.arg("--user").arg("--name");
    if let Some(path) = getenv("HOST_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Ignored).stderr(InheritFd(2));
    let username = try!(cmd.output()
        .map_err(|e| format!("Error running `id --user --name`: {}", e))
        .and_then(|out| if out.status == ExitStatus(0) { Ok(out.output) } else
            { Err(format!("Error running `id --user --name`")) })
        .and_then(|val| from_utf8(val.as_slice()).map(|x| x.trim().to_string())
                   .ok_or(format!("Can't decode username"))));
    let uid_map = read_uid_map(username.as_slice()).ok();
    let gid_map = read_gid_map(username.as_slice()).ok();

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Some(uid_map), Some(gid_map)) = (uid_map, gid_map) {
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start && uid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start, rng.start, rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start && gid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start, rng.start, rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!(concat!("Your system doesn't have /etc/subuid and /etc/subgid.",
            " Presumably your system is too old. Some features may not work"));
        return Ok(Singleton(uid, gid));
    }
}

pub fn apply_uidmap(pid: pid_t, map: &Uidmap) -> Result<(), IoError> {
    match map {
        &Singleton(uid, gid) => {
            let uid_map = format!("0 {} 1", uid);
            debug!("Writing uid_map: {}", uid_map);
            match File::open_mode(&Path::new("/proc")
                              .join(pid.to_string())
                              .join("uid_map"), Open, Write)
                    .write_str(uid_map.as_slice()) {
                Ok(()) => {}
                Err(e) => return Err(IoError {
                    kind: e.kind,
                    desc: "Error writing uid mapping",
                    detail: e.detail,
                    }),
            }
            let gid_map = format!("0 {} 1", gid);
            debug!("Writing gid_map: {}", gid_map);
            match File::open_mode(&Path::new("/proc")
                              .join(pid.to_string())
                              .join("gid_map"), Open, Write)
                    .write_str(uid_map.as_slice()) {
                Ok(()) => {}
                Err(e) => return Err(IoError {
                    kind: e.kind,
                    desc: "Error writing gid mapping",
                    detail: e.detail
                    }),
            }
        }
        &Ranges(ref uids, ref gids) => {
            let myuid = unsafe { geteuid() };
            if myuid > 0 {
                let mut cmd = Command::new("newuidmap");
                cmd.stdin(Ignored).stdout(InheritFd(1)).stderr(InheritFd(2));
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in uids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Uid map command: {}", cmd);
                match cmd.status() {
                    Ok(ExitStatus(0)) => {},
                    Ok(ExitStatus(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing uid mapping",
                            detail: Some(format!(
                                "newuidmap exited with status {}", x)),
                            });
                    }
                    Ok(ExitSignal(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing uid mapping",
                            detail: Some(format!(
                                "newuidmap exited with signal {}", x)),
                            });
                    }
                    Err(e) => return Err(IoError {
                        kind: e.kind,
                        desc: "Error writing uid mapping",
                        detail: e.detail
                        }),
                }

                let mut cmd = Command::new("newgidmap");
                cmd.stdin(Ignored).stdout(InheritFd(1)).stderr(InheritFd(2));
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in gids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Gid map command: {}", cmd);
                match cmd.status() {
                    Ok(ExitStatus(0)) => {},
                    Ok(ExitStatus(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing gid mapping",
                            detail: Some(format!(
                                "newgidmap exited with status {}", x)),
                            });
                    }
                    Ok(ExitSignal(x)) => {
                        return Err(IoError {
                            kind: OtherIoError,
                            desc: "Error writing gid mapping",
                            detail: Some(format!(
                                "newgidmap exited with signal {}", x)),
                            });
                    }
                    Err(e) => return Err(IoError {
                        kind: e.kind,
                        desc: "Error writing gid mapping",
                        detail: e.detail
                        }),
                }
            } else {
                let mut membuf = MemWriter::new();
                for &(ins, outs, cnt) in uids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/uid_map", pid))));
                let value = membuf.unwrap();
                debug!("Writing uid map ```{}```",
                    String::from_utf8_lossy(value.as_slice()));
                try!(file.write(value.as_slice()));

                let mut membuf = MemWriter::new();
                for &(ins, outs, cnt) in gids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/gid_map", pid))));
                let value = membuf.unwrap();
                debug!("Writing gid map ```{}```",
                    String::from_utf8_lossy(value.as_slice()));
                try!(file.write(value.as_slice()));
            }
        }
    }
    return Ok(());
}

fn read_outside_ranges(path: &str) -> Result<Vec<Range>, String> {
    let mut file = BufferedReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|e| format!("Error reading uid/gid map: {}", e)));
        let mut words = line.as_slice().words();
        let outside = try!(words.next().and_then(FromStr::from_str)
            .ok_or(format!("uid/gid map format error")));
        try!(words.next()
            .ok_or(format!("uid/gid map format error")));
        let count = try!(words.next().and_then(FromStr::from_str)
            .ok_or(format!("uid/gid map format error")));
        result.push(Range { start: outside, end: outside+count-1 });
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range { start: 0, end: 0 });
    let default_gids = vec!(Range { start: 0, end: 0 });
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    if settings.uid_map.is_none() {
        let ranges = try!(read_outside_ranges("/proc/self/uid_map"));
        let uid_map = match_ranges(uids, &ranges, 0);
        let ranges = try!(read_outside_ranges("/proc/self/gid_map"));
        let gid_map = match_ranges(gids, &ranges, 0);
        return Ok(Ranges(uid_map, gid_map));
    } else {
        let &(ref uids, ref gids) = settings.uid_map.as_ref().unwrap();
        return Ok(Ranges(uids.clone(), gids.clone()));
    }
}
<|endoftext|>


<commit_before>use std::collections::{self, HashMap};
use std::hash::{BuildHasherDefault, BuildHasher};

fn test_map<S: BuildHasher>(mut map: HashMap<i32, i32, S>) {
    map.insert(0, 0);
    assert_eq!(map.values().fold(0, |x, y| x+y), 0);

    let num = 25;
    for i in 1..num {
        map.insert(i, i);
    }
    assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now

    // Inserting again replaces the existing entries
    for i in 0..num {
        map.insert(i, num-1-i);
    }
    assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2);

    // TODO: Test Entry API, Iterators, ...

}

fn main() {
    if cfg!(target_os = "macos") { // TODO: Implement libstd HashMap seeding for macOS (https://github.com/rust-lang/miri/issues/686).
        // Until then, use a deterministic map.
        test_map::<BuildHasherDefault<collections::hash_map::DefaultHasher>>(HashMap::default());
    } else {
        test_map(HashMap::new());
    }
}
<commit_msg>Auto merge of #1134 - RalfJung:macos-hashmap, r=RalfJung<commit_after>// macOS needs FS access for its HashMap:
// compile-flags: -Zmiri-disable-isolation

use std::collections::HashMap;
use std::hash::BuildHasher;

fn test_map<S: BuildHasher>(mut map: HashMap<i32, i32, S>) {
    map.insert(0, 0);
    assert_eq!(map.values().fold(0, |x, y| x+y), 0);

    let num = 25;
    for i in 1..num {
        map.insert(i, i);
    }
    assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now

    // Inserting again replaces the existing entries
    for i in 0..num {
        map.insert(i, num-1-i);
    }
    assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2);

    // TODO: Test Entry API, Iterators, ...
}

fn main() {
    test_map(HashMap::new());
}
<|endoftext|>


<commit_before>//! Stand-alone WebAssembly to Cranelift IR translator.
//!
//! This module defines the `FuncTranslator` type which can translate a single WebAssembly
//! function to Cranelift IR guided by a `FuncEnvironment` which provides information about the
//! WebAssembly module and the runtime environment.

use crate::code_translator::translate_operator;
use crate::environ::{FuncEnvironment, ReturnMode, WasmError, WasmResult};
use crate::state::TranslationState;
use crate::translation_utils::get_vmctx_value_label;
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel};
use cranelift_codegen::timing;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use log::info;
use wasmparser::{self, BinaryReader};

/// WebAssembly to Cranelift IR function translator.
///
/// A `FuncTranslator` is used to translate a binary WebAssembly function into Cranelift IR guided
/// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple
/// functions which will reduce heap allocation traffic.
pub struct FuncTranslator {
    func_ctx: FunctionBuilderContext,
    state: TranslationState,
}

impl FuncTranslator {
    /// Create a new translator.
    pub fn new() -> Self {
        Self {
            func_ctx: FunctionBuilderContext::new(),
            state: TranslationState::new(),
        }
    }

    /// Translate a binary WebAssembly function.
    ///
    /// The `code` slice contains the binary WebAssembly *function code* as it appears in the code
    /// section of a WebAssembly module, not including the initial size of the function code. The
    /// slice is expected to contain two parts:
    ///
    /// - The declaration of *locals*, and
    /// - The function *body* as an expression.
    ///
    /// See [the WebAssembly specification][wasm].
    ///
    /// [wasm]: https://webassembly.github.io/spec/binary/modules.html#code-section
    ///
    /// The Cranelift IR function `func` should be completely empty except for the `func.signature`
    /// and `func.name` fields. The signature may contain special-purpose arguments which are not
    /// regarded as WebAssembly local variables. Any signature arguments marked as
    /// `ArgumentPurpose::Normal` are made accessible as WebAssembly local variables.
    ///
    pub fn translate<FE: FuncEnvironment + ?Sized>(
        &mut self,
        code: &[u8],
        code_offset: usize,
        func: &mut ir::Function,
        environ: &mut FE,
    ) -> WasmResult<()> {
        self.translate_from_reader(
            BinaryReader::new_with_offset(code, code_offset),
            func,
            environ,
        )
    }

    /// Translate a binary WebAssembly function from a `BinaryReader`.
    pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
        &mut self,
        mut reader: BinaryReader,
        func: &mut ir::Function,
        environ: &mut FE,
    ) -> WasmResult<()> {
        let _tt = timing::wasm_translate_function();
        info!(
            "translate({} bytes, {}{})",
            reader.bytes_remaining(),
            func.name,
            func.signature
        );
        debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty");
        debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");

        // This clears the `FunctionBuilderContext`.
        let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
        builder.set_srcloc(cur_srcloc(&reader));
        let entry_block = builder.create_ebb();
        builder.append_ebb_params_for_function_params(entry_block);
        builder.switch_to_block(entry_block); // This also creates values for the arguments.
        builder.seal_block(entry_block);
        // Make sure the entry block is inserted in the layout before we make any callbacks to
        // `environ`. The callback functions may need to insert things in the entry block.
        builder.ensure_inserted_ebb();

        let num_params = declare_wasm_parameters(&mut builder, entry_block);

        // Set up the translation state with a single pushed control block representing the whole
        // function and its return values.
        let exit_block = builder.create_ebb();
        builder.append_ebb_params_for_function_returns(exit_block);
        self.state.initialize(&builder.func.signature, exit_block);

        parse_local_decls(&mut reader, &mut builder, num_params)?;
        parse_function_body(reader, &mut builder, &mut self.state, environ)?;

        builder.finalize();
        Ok(())
    }
}

/// Declare local variables for the signature parameters that correspond to WebAssembly locals.
///
/// Return the number of local variables declared.
fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> usize {
    let sig_len = builder.func.signature.params.len();
    let mut next_local = 0;
    for i in 0..sig_len {
        let param_type = builder.func.signature.params[i];
        // There may be additional special-purpose parameters following the normal WebAssembly
        // signature parameters. For example, a `vmctx` pointer.
        if param_type.purpose == ir::ArgumentPurpose::Normal {
            // This is a normal WebAssembly signature parameter, so create a local for it.
            let local = Variable::new(next_local);
            builder.declare_var(local, param_type.value_type);
            next_local += 1;

            let param_value = builder.ebb_params(entry_block)[i];
            builder.def_var(local, param_value);
        }
        if param_type.purpose == ir::ArgumentPurpose::VMContext {
            let param_value = builder.ebb_params(entry_block)[i];
            builder.set_val_label(param_value, get_vmctx_value_label());
        }
    }

    next_local
}

/// Parse the local variable declarations that precede the function body.
///
/// Declare local variables, starting from `num_params`.
fn parse_local_decls(
    reader: &mut BinaryReader,
    builder: &mut FunctionBuilder,
    num_params: usize,
) -> WasmResult<()> {
    let mut next_local = num_params;
    let local_count = reader.read_local_count()?;

    let mut locals_total = 0;
    for _ in 0..local_count {
        builder.set_srcloc(cur_srcloc(reader));
        let (count, ty) = reader.read_local_decl(&mut locals_total)?;
        declare_locals(builder, count, ty, &mut next_local)?;
    }

    Ok(())
}

/// Declare `count` local variables of the same type, starting from `next_local`.
///
/// Fail of too many locals are declared in the function, or if the type is not valid for a local.
fn declare_locals(
    builder: &mut FunctionBuilder,
    count: u32,
    wasm_type: wasmparser::Type,
    next_local: &mut usize,
) -> WasmResult<()> {
    // All locals are initialized to 0.
    use wasmparser::Type::*;
    let zeroval = match wasm_type {
        I32 => builder.ins().iconst(ir::types::I32, 0),
        I64 => builder.ins().iconst(ir::types::I64, 0),
        F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
        F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
        _ => return Err(WasmError::Unsupported("unsupported local type")),
    };

    let ty = builder.func.dfg.value_type(zeroval);
    for _ in 0..count {
        let local = Variable::new(*next_local);
        builder.declare_var(local, ty);
        builder.def_var(local, zeroval);
        builder.set_val_label(zeroval, ValueLabel::new(*next_local));
        *next_local += 1;
    }
    Ok(())
}

/// Parse the function body in `reader`.
///
/// This assumes that the local variable declarations have already been parsed and function
/// arguments and locals are declared in the builder.
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
    mut reader: BinaryReader,
    builder: &mut FunctionBuilder,
    state: &mut TranslationState,
    environ: &mut FE,
) -> WasmResult<()> {
    // The control stack is initialized with a single block representing the whole function.
    debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");

    // Keep going until the final `End` operator which pops the outermost block.
    while !state.control_stack.is_empty() {
        builder.set_srcloc(cur_srcloc(&reader));
        let op = reader.read_operator()?;
        translate_operator(op, builder, state, environ)?;
    }

    // The final `End` operator left us in the exit block where we need to manually add a return
    // instruction.
    //
    // If the exit block is unreachable, it may not have the correct arguments, so we would
    // generate a return instruction that doesn't match the signature.
    if state.reachable {
        debug_assert!(builder.is_pristine());
        if !builder.is_unreachable() {
            match environ.return_mode() {
                ReturnMode::NormalReturns => builder.ins().return_(&state.stack),
                ReturnMode::FallthroughReturn => builder.ins().fallthrough_return(&state.stack),
            };
        }
    }

    // Discard any remaining values on the stack. Either we just returned them,
    // or the end of the function is unreachable.
    state.stack.clear();

    debug_assert!(reader.eof());

    Ok(())
}

/// Get the current source location from a reader.
fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
    // We record source locations as byte code offsets relative to the beginning of the file.
    // This will wrap around if byte code is larger than 4 GB.
    ir::SourceLoc::new(reader.original_position() as u32)
}

#[cfg(test)]
mod tests {
    use super::{FuncTranslator, ReturnMode};
    use crate::environ::DummyEnvironment;
    use cranelift_codegen::ir::types::I32;
    use cranelift_codegen::{ir, isa, settings, Context};
    use log::debug;
    use target_lexicon::PointerWidth;

    #[test]
    fn small1() {
        // Implicit return.
        //
        // (func $small1 (param i32) (result i32)
        //     (i32.add (get_local 0) (i32.const 1))
        // )
        const BODY: [u8; 7] = [
            0x00, // local decl count
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 1
            0x6a, // i32.add
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );

        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("small1");
        ctx.func.signature.params.push(ir::AbiParam::new(I32));
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }

    #[test]
    fn small2() {
        // Same as above, but with an explicit return instruction.
        //
        // (func $small2 (param i32) (result i32)
        //     (return (i32.add (get_local 0) (i32.const 1)))
        // )
        const BODY: [u8; 8] = [
            0x00, // local decl count
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 1
            0x6a, // i32.add
            0x0f, // return
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );
        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("small2");
        ctx.func.signature.params.push(ir::AbiParam::new(I32));
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }

    #[test]
    fn infloop() {
        // An infinite loop, no return instructions.
        //
        // (func $infloop (result i32)
        //     (local i32)
        //     (loop (result i32)
        //         (i32.add (get_local 0) (i32.const 1))
        //         (set_local 0)
        //         (br 0)
        //     )
        // )
        const BODY: [u8; 16] = [
            0x01, // 1 local decl.
            0x01, 0x7f, // 1 i32 local.
            0x03, 0x7f, // loop i32
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 0
            0x6a, // i32.add
            0x21, 0x00, // set_local 0
            0x0c, 0x00, // br 0
            0x0b, // end
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );
        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("infloop");
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }
}
<commit_msg>Fix url in comments<commit_after>//! Stand-alone WebAssembly to Cranelift IR translator.
//!
//! This module defines the `FuncTranslator` type which can translate a single WebAssembly
//! function to Cranelift IR guided by a `FuncEnvironment` which provides information about the
//! WebAssembly module and the runtime environment.

use crate::code_translator::translate_operator;
use crate::environ::{FuncEnvironment, ReturnMode, WasmError, WasmResult};
use crate::state::TranslationState;
use crate::translation_utils::get_vmctx_value_label;
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel};
use cranelift_codegen::timing;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use log::info;
use wasmparser::{self, BinaryReader};

/// WebAssembly to Cranelift IR function translator.
///
/// A `FuncTranslator` is used to translate a binary WebAssembly function into Cranelift IR guided
/// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple
/// functions which will reduce heap allocation traffic.
pub struct FuncTranslator {
    func_ctx: FunctionBuilderContext,
    state: TranslationState,
}

impl FuncTranslator {
    /// Create a new translator.
    pub fn new() -> Self {
        Self {
            func_ctx: FunctionBuilderContext::new(),
            state: TranslationState::new(),
        }
    }

    /// Translate a binary WebAssembly function.
    ///
    /// The `code` slice contains the binary WebAssembly *function code* as it appears in the code
    /// section of a WebAssembly module, not including the initial size of the function code. The
    /// slice is expected to contain two parts:
    ///
    /// - The declaration of *locals*, and
    /// - The function *body* as an expression.
    ///
    /// See [the WebAssembly specification][wasm].
    ///
    /// [wasm]: https://webassembly.github.io/spec/core/binary/modules.html#code-section
    ///
    /// The Cranelift IR function `func` should be completely empty except for the `func.signature`
    /// and `func.name` fields. The signature may contain special-purpose arguments which are not
    /// regarded as WebAssembly local variables. Any signature arguments marked as
    /// `ArgumentPurpose::Normal` are made accessible as WebAssembly local variables.
    ///
    pub fn translate<FE: FuncEnvironment + ?Sized>(
        &mut self,
        code: &[u8],
        code_offset: usize,
        func: &mut ir::Function,
        environ: &mut FE,
    ) -> WasmResult<()> {
        self.translate_from_reader(
            BinaryReader::new_with_offset(code, code_offset),
            func,
            environ,
        )
    }

    /// Translate a binary WebAssembly function from a `BinaryReader`.
    pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
        &mut self,
        mut reader: BinaryReader,
        func: &mut ir::Function,
        environ: &mut FE,
    ) -> WasmResult<()> {
        let _tt = timing::wasm_translate_function();
        info!(
            "translate({} bytes, {}{})",
            reader.bytes_remaining(),
            func.name,
            func.signature
        );
        debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty");
        debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");

        // This clears the `FunctionBuilderContext`.
        let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
        builder.set_srcloc(cur_srcloc(&reader));
        let entry_block = builder.create_ebb();
        builder.append_ebb_params_for_function_params(entry_block);
        builder.switch_to_block(entry_block); // This also creates values for the arguments.
        builder.seal_block(entry_block);
        // Make sure the entry block is inserted in the layout before we make any callbacks to
        // `environ`. The callback functions may need to insert things in the entry block.
        builder.ensure_inserted_ebb();

        let num_params = declare_wasm_parameters(&mut builder, entry_block);

        // Set up the translation state with a single pushed control block representing the whole
        // function and its return values.
        let exit_block = builder.create_ebb();
        builder.append_ebb_params_for_function_returns(exit_block);
        self.state.initialize(&builder.func.signature, exit_block);

        parse_local_decls(&mut reader, &mut builder, num_params)?;
        parse_function_body(reader, &mut builder, &mut self.state, environ)?;

        builder.finalize();
        Ok(())
    }
}

/// Declare local variables for the signature parameters that correspond to WebAssembly locals.
///
/// Return the number of local variables declared.
fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> usize {
    let sig_len = builder.func.signature.params.len();
    let mut next_local = 0;
    for i in 0..sig_len {
        let param_type = builder.func.signature.params[i];
        // There may be additional special-purpose parameters following the normal WebAssembly
        // signature parameters. For example, a `vmctx` pointer.
        if param_type.purpose == ir::ArgumentPurpose::Normal {
            // This is a normal WebAssembly signature parameter, so create a local for it.
            let local = Variable::new(next_local);
            builder.declare_var(local, param_type.value_type);
            next_local += 1;

            let param_value = builder.ebb_params(entry_block)[i];
            builder.def_var(local, param_value);
        }
        if param_type.purpose == ir::ArgumentPurpose::VMContext {
            let param_value = builder.ebb_params(entry_block)[i];
            builder.set_val_label(param_value, get_vmctx_value_label());
        }
    }

    next_local
}

/// Parse the local variable declarations that precede the function body.
///
/// Declare local variables, starting from `num_params`.
fn parse_local_decls(
    reader: &mut BinaryReader,
    builder: &mut FunctionBuilder,
    num_params: usize,
) -> WasmResult<()> {
    let mut next_local = num_params;
    let local_count = reader.read_local_count()?;

    let mut locals_total = 0;
    for _ in 0..local_count {
        builder.set_srcloc(cur_srcloc(reader));
        let (count, ty) = reader.read_local_decl(&mut locals_total)?;
        declare_locals(builder, count, ty, &mut next_local)?;
    }

    Ok(())
}

/// Declare `count` local variables of the same type, starting from `next_local`.
///
/// Fail of too many locals are declared in the function, or if the type is not valid for a local.
fn declare_locals(
    builder: &mut FunctionBuilder,
    count: u32,
    wasm_type: wasmparser::Type,
    next_local: &mut usize,
) -> WasmResult<()> {
    // All locals are initialized to 0.
    use wasmparser::Type::*;
    let zeroval = match wasm_type {
        I32 => builder.ins().iconst(ir::types::I32, 0),
        I64 => builder.ins().iconst(ir::types::I64, 0),
        F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
        F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
        _ => return Err(WasmError::Unsupported("unsupported local type")),
    };

    let ty = builder.func.dfg.value_type(zeroval);
    for _ in 0..count {
        let local = Variable::new(*next_local);
        builder.declare_var(local, ty);
        builder.def_var(local, zeroval);
        builder.set_val_label(zeroval, ValueLabel::new(*next_local));
        *next_local += 1;
    }
    Ok(())
}

/// Parse the function body in `reader`.
///
/// This assumes that the local variable declarations have already been parsed and function
/// arguments and locals are declared in the builder.
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
    mut reader: BinaryReader,
    builder: &mut FunctionBuilder,
    state: &mut TranslationState,
    environ: &mut FE,
) -> WasmResult<()> {
    // The control stack is initialized with a single block representing the whole function.
    debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");

    // Keep going until the final `End` operator which pops the outermost block.
    while !state.control_stack.is_empty() {
        builder.set_srcloc(cur_srcloc(&reader));
        let op = reader.read_operator()?;
        translate_operator(op, builder, state, environ)?;
    }

    // The final `End` operator left us in the exit block where we need to manually add a return
    // instruction.
    //
    // If the exit block is unreachable, it may not have the correct arguments, so we would
    // generate a return instruction that doesn't match the signature.
    if state.reachable {
        debug_assert!(builder.is_pristine());
        if !builder.is_unreachable() {
            match environ.return_mode() {
                ReturnMode::NormalReturns => builder.ins().return_(&state.stack),
                ReturnMode::FallthroughReturn => builder.ins().fallthrough_return(&state.stack),
            };
        }
    }

    // Discard any remaining values on the stack. Either we just returned them,
    // or the end of the function is unreachable.
    state.stack.clear();

    debug_assert!(reader.eof());

    Ok(())
}

/// Get the current source location from a reader.
fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
    // We record source locations as byte code offsets relative to the beginning of the file.
    // This will wrap around if byte code is larger than 4 GB.
    ir::SourceLoc::new(reader.original_position() as u32)
}

#[cfg(test)]
mod tests {
    use super::{FuncTranslator, ReturnMode};
    use crate::environ::DummyEnvironment;
    use cranelift_codegen::ir::types::I32;
    use cranelift_codegen::{ir, isa, settings, Context};
    use log::debug;
    use target_lexicon::PointerWidth;

    #[test]
    fn small1() {
        // Implicit return.
        //
        // (func $small1 (param i32) (result i32)
        //     (i32.add (get_local 0) (i32.const 1))
        // )
        const BODY: [u8; 7] = [
            0x00, // local decl count
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 1
            0x6a, // i32.add
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );

        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("small1");
        ctx.func.signature.params.push(ir::AbiParam::new(I32));
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }

    #[test]
    fn small2() {
        // Same as above, but with an explicit return instruction.
        //
        // (func $small2 (param i32) (result i32)
        //     (return (i32.add (get_local 0) (i32.const 1)))
        // )
        const BODY: [u8; 8] = [
            0x00, // local decl count
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 1
            0x6a, // i32.add
            0x0f, // return
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );
        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("small2");
        ctx.func.signature.params.push(ir::AbiParam::new(I32));
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }

    #[test]
    fn infloop() {
        // An infinite loop, no return instructions.
        //
        // (func $infloop (result i32)
        //     (local i32)
        //     (loop (result i32)
        //         (i32.add (get_local 0) (i32.const 1))
        //         (set_local 0)
        //         (br 0)
        //     )
        // )
        const BODY: [u8; 16] = [
            0x01, // 1 local decl.
            0x01, 0x7f, // 1 i32 local.
            0x03, 0x7f, // loop i32
            0x20, 0x00, // get_local 0
            0x41, 0x01, // i32.const 0
            0x6a, // i32.add
            0x21, 0x00, // set_local 0
            0x0c, 0x00, // br 0
            0x0b, // end
            0x0b, // end
        ];

        let mut trans = FuncTranslator::new();
        let flags = settings::Flags::new(settings::builder());
        let runtime = DummyEnvironment::new(
            isa::TargetFrontendConfig {
                default_call_conv: isa::CallConv::Fast,
                pointer_width: PointerWidth::U64,
            },
            ReturnMode::NormalReturns,
            false,
        );
        let mut ctx = Context::new();

        ctx.func.name = ir::ExternalName::testcase("infloop");
        ctx.func.signature.returns.push(ir::AbiParam::new(I32));

        trans
            .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env())
            .unwrap();
        debug!("{}", ctx.func.display(None));
        ctx.verify(&flags).unwrap();
    }
}
<|endoftext|>


<commit_before>use hir::db::HirDatabase;
use ra_syntax::ast::{AstNode, BinExpr, BinOp};

use crate::{AssistCtx, Assist, AssistId};

/// Flip binary comparison expressions (==, !=, >, >=, <, <=).
pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let expr = ctx.node_at_offset::<BinExpr>()?;
    let lhs = expr.lhs()?.syntax();
    let rhs = expr.rhs()?.syntax();
    let op_range = expr.op()?.range();
    // The assist should be available only if the cursor is on the operator
    let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
    // The assist should be available only for these binary operators
    // (it should not change the meaning of the expression)
    let allowed_ops = [
        BinOp::EqualityTest,
        BinOp::NegatedEqualityTest,
        BinOp::GreaterTest,
        BinOp::GreaterEqualTest,
        BinOp::LesserTest,
        BinOp::LesserEqualTest,
    ];
    let op_kind = expr.op_kind()?;
    if !cursor_in_range || !allowed_ops.iter().any(|o| *o == op_kind) {
        return None;
    }
    let new_op = match op_kind {
        BinOp::GreaterTest => Some("<"),
        BinOp::GreaterEqualTest => Some("<="),
        BinOp::LesserTest => Some(">"),
        BinOp::LesserEqualTest => Some(">="),
        _ => None,
    };
    ctx.add_action(AssistId("flip_binexpr"), "flip binary expression", |edit| {
        edit.target(op_range);
        if let Some(new_op) = new_op {
            edit.replace(op_range, new_op);
        }
        edit.replace(lhs.range(), rhs.text());
        edit.replace(rhs.range(), lhs.text());
    });

    ctx.build()
}

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

    use crate::helpers::{check_assist, check_assist_target};

    #[test]
    fn flip_eq_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 ==<|> 2; }",
            "fn f() { let res = 2 ==<|> 1; }",
        )
    }

    #[test]
    fn flip_neq_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 !=<|> 2; }",
            "fn f() { let res = 2 !=<|> 1; }",
        )
    }

    #[test]
    fn flip_gt_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 ><|> 2; }",
            "fn f() { let res = 2 <<|> 1; }",
        )
    }

    #[test]
    fn flip_gteq_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 >=<|> 2; }",
            "fn f() { let res = 2 <=<|> 1; }",
        )
    }

    #[test]
    fn flip_lt_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 <<|> 2; }",
            "fn f() { let res = 2 ><|> 1; }",
        )
    }

    #[test]
    fn flip_lteq_operands_for_simple_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 <=<|> 2; }",
            "fn f() { let res = 2 >=<|> 1; }",
        )
    }

    #[test]
    fn flip_eq_operands_for_complex_stmt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = (1 + 1) ==<|> (2 + 2); }",
            "fn f() { let res = (2 + 2) ==<|> (1 + 1); }",
        )
    }

    #[test]
    fn flip_eq_operands_in_match_expr() {
        check_assist(
            flip_binexpr,
            r#"
            fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
                match other.downcast_ref::<Self>() {
                    None => false,
                    Some(it) => it ==<|> self,
                }
            }
            "#,
            r#"
            fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
                match other.downcast_ref::<Self>() {
                    None => false,
                    Some(it) => self ==<|> it,
                }
            }
            "#,
        )
    }

    #[test]
    fn flip_eq_operands_target() {
        check_assist_target(flip_binexpr, "fn f() { let res = 1 ==<|> 2; }", "==")
    }

    #[test]
    fn flip_gt_operands_target() {
        check_assist_target(flip_binexpr, "fn f() { let res = 1 ><|> 2; }", ">")
    }

}
<commit_msg>Flip any binary expression except assignments.<commit_after>use hir::db::HirDatabase;
use ra_syntax::ast::{AstNode, BinExpr, BinOp};

use crate::{AssistCtx, Assist, AssistId};

/// Flip binary expression assist.
pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let expr = ctx.node_at_offset::<BinExpr>()?;
    let lhs = expr.lhs()?.syntax();
    let rhs = expr.rhs()?.syntax();
    let op_range = expr.op()?.range();
    // The assist should be applied only if the cursor is on the operator
    let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
    if !cursor_in_range {
        return None;
    }
    let action: FlipAction = expr.op_kind()?.into();
    // The assist should not be applied for certain operators
    if let FlipAction::DontFlip = action {
        return None;
    }

    ctx.add_action(AssistId("flip_binexpr"), "flip binary expression", |edit| {
        edit.target(op_range);
        if let FlipAction::FlipAndReplaceOp(new_op) = action {
            edit.replace(op_range, new_op);
        }
        edit.replace(lhs.range(), rhs.text());
        edit.replace(rhs.range(), lhs.text());
    });

    ctx.build()
}

enum FlipAction {
    // Flip the expression
    Flip,
    // Flip the expression and replace the operator with this string
    FlipAndReplaceOp(&'static str),
    // Do not flip the expression
    DontFlip,
}

impl From<BinOp> for FlipAction {
    fn from(op_kind: BinOp) -> Self {
        match op_kind {
            BinOp::Assignment => FlipAction::DontFlip,
            BinOp::AddAssign => FlipAction::DontFlip,
            BinOp::DivAssign => FlipAction::DontFlip,
            BinOp::MulAssign => FlipAction::DontFlip,
            BinOp::RemAssign => FlipAction::DontFlip,
            BinOp::ShrAssign => FlipAction::DontFlip,
            BinOp::ShlAssign => FlipAction::DontFlip,
            BinOp::SubAssign => FlipAction::DontFlip,
            BinOp::BitOrAssign => FlipAction::DontFlip,
            BinOp::BitAndAssign => FlipAction::DontFlip,
            BinOp::BitXorAssign => FlipAction::DontFlip,
            BinOp::GreaterTest => FlipAction::FlipAndReplaceOp("<"),
            BinOp::GreaterEqualTest => FlipAction::FlipAndReplaceOp("<="),
            BinOp::LesserTest => FlipAction::FlipAndReplaceOp(">"),
            BinOp::LesserEqualTest => FlipAction::FlipAndReplaceOp(">="),
            _ => FlipAction::Flip,
        }
    }
}

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

    use crate::helpers::{ check_assist, check_assist_target, check_assist_not_applicable };

    #[test]
    fn flip_binexpr_target_is_the_op() {
        check_assist_target(flip_binexpr, "fn f() { let res = 1 ==<|> 2; }", "==")
    }

    #[test]
    fn flip_binexpr_not_applicable_for_assignment() {
        check_assist_not_applicable(flip_binexpr, "fn f() { let mut _x = 1; _x +=<|> 2 }")
    }

    #[test]
    fn flip_binexpr_works_for_eq() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 ==<|> 2; }",
            "fn f() { let res = 2 ==<|> 1; }",
        )
    }

    #[test]
    fn flip_binexpr_works_for_gt() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 ><|> 2; }",
            "fn f() { let res = 2 <<|> 1; }",
        )
    }

    #[test]
    fn flip_binexpr_works_for_lteq() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = 1 <=<|> 2; }",
            "fn f() { let res = 2 >=<|> 1; }",
        )
    }

    #[test]
    fn flip_binexpr_works_for_complex_expr() {
        check_assist(
            flip_binexpr,
            "fn f() { let res = (1 + 1) ==<|> (2 + 2); }",
            "fn f() { let res = (2 + 2) ==<|> (1 + 1); }",
        )
    }

    #[test]
    fn flip_binexpr_works_inside_match() {
        check_assist(
            flip_binexpr,
            r#"
            fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
                match other.downcast_ref::<Self>() {
                    None => false,
                    Some(it) => it ==<|> self,
                }
            }
            "#,
            r#"
            fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
                match other.downcast_ref::<Self>() {
                    None => false,
                    Some(it) => self ==<|> it,
                }
            }
            "#,
        )
    }
}
<|endoftext|>


<commit_before><commit_msg>client-api: Fix module ordering<commit_after><|endoftext|>


<commit_before>
macro_rules! impl_cons_iter(
    ($_A:ident, $_B:ident, ) => (); // stop

    ($A:ident, $($B:ident,)*) => (
        impl_cons_iter!($($B,)*);
        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> Iterator for ConsTuples<Iter, (($($B,)*), X)>
            where Iter: Iterator<Item = (($($B,)*), X)>,
        {
            type Item = ($($B,)* X, );
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
            fn fold<Acc, Fold>(self, accum: Acc, mut f: Fold) -> Acc
                where Fold: FnMut(Acc, Self::Item) -> Acc,
            {
                self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, )))
            }
        }

        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> DoubleEndedIterator for ConsTuples<Iter, (($($B,)*), X)>
            where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
        {
            fn next_back(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }
        }

    );
);

impl_cons_iter!(A, B, C, D, E, F, G, H,);

/// An iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ConsTuples<I, J>
    where I: Iterator<Item=J>,
{
    iter: I,
}

impl<I, J> Clone for ConsTuples<I, J>
    where I: Clone + Iterator<Item=J>,
{
    clone_fields!(iter);
}

/// Create an iterator that maps for example iterators of
/// `((A, B), C)` to `(A, B, C)`.
pub fn cons_tuples<I, J>(iterable: I) -> ConsTuples<I, J>
    where I: Iterator<Item=J>
{
    ConsTuples { iter: iterable.into_iter() }
}
<commit_msg>Free function should take IntoIterator<commit_after>
macro_rules! impl_cons_iter(
    ($_A:ident, $_B:ident, ) => (); // stop

    ($A:ident, $($B:ident,)*) => (
        impl_cons_iter!($($B,)*);
        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> Iterator for ConsTuples<Iter, (($($B,)*), X)>
            where Iter: Iterator<Item = (($($B,)*), X)>,
        {
            type Item = ($($B,)* X, );
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
            fn fold<Acc, Fold>(self, accum: Acc, mut f: Fold) -> Acc
                where Fold: FnMut(Acc, Self::Item) -> Acc,
            {
                self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, )))
            }
        }

        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> DoubleEndedIterator for ConsTuples<Iter, (($($B,)*), X)>
            where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
        {
            fn next_back(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }
        }

    );
);

impl_cons_iter!(A, B, C, D, E, F, G, H,);

/// An iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ConsTuples<I, J>
    where I: Iterator<Item=J>,
{
    iter: I,
}

impl<I, J> Clone for ConsTuples<I, J>
    where I: Clone + Iterator<Item=J>,
{
    clone_fields!(iter);
}

/// Create an iterator that maps for example iterators of
/// `((A, B), C)` to `(A, B, C)`.
pub fn cons_tuples<I, J>(iterable: I) -> ConsTuples<I::IntoIter, J>
    where I: IntoIterator<Item=J>
{
    ConsTuples { iter: iterable.into_iter() }
}
<|endoftext|>