<commit_before>use parking_lot::RwLock;

use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::Index;
use std::sync::Arc;

use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

use crate::language::sem_analysis::{
    extension_matches_ty, FctDefinitionId, ModuleDefinitionId, SemAnalysis, SourceFileId,
    TraitDefinitionId, TypeParamDefinition,
};
use crate::language::ty::{SourceType, SourceTypeArray};
use crate::utils::Id;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImplDefinitionId(u32);

impl Id for ImplDefinition {
    type IdType = ImplDefinitionId;

    fn id_to_usize(id: ImplDefinitionId) -> usize {
        id.0 as usize
    }

    fn usize_to_id(value: usize) -> ImplDefinitionId {
        ImplDefinitionId(value.try_into().unwrap())
    }

    fn store_id(value: &mut ImplDefinition, id: ImplDefinitionId) {
        value.id = Some(id);
    }
}

#[derive(Debug)]
pub struct ImplDefinition {
    pub id: Option<ImplDefinitionId>,
    pub file_id: SourceFileId,
    pub ast: Arc<ast::Impl>,
    pub module_id: ModuleDefinitionId,
    pub pos: Position,
    pub type_params: TypeParamDefinition,
    pub trait_ty: SourceType,
    pub extended_ty: SourceType,
    pub methods: Vec<FctDefinitionId>,
    pub instance_names: HashMap<Name, FctDefinitionId>,
    pub static_names: HashMap<Name, FctDefinitionId>,
    pub impl_for: HashMap<FctDefinitionId, FctDefinitionId>,
}

impl ImplDefinition {
    pub fn new(
        file_id: SourceFileId,
        module_id: ModuleDefinitionId,
        node: &Arc<ast::Impl>,
    ) -> ImplDefinition {
        ImplDefinition {
            id: None,
            file_id,
            ast: node.clone(),
            module_id,
            type_params: TypeParamDefinition::new_ast(&node.type_params),
            pos: node.pos,
            trait_ty: SourceType::Error,
            extended_ty: SourceType::Error,
            methods: Vec::new(),
            instance_names: HashMap::new(),
            static_names: HashMap::new(),
            impl_for: HashMap::new(),
        }
    }

    pub fn id(&self) -> ImplDefinitionId {
        self.id.expect("id missing")
    }

    pub fn trait_id(&self) -> TraitDefinitionId {
        self.trait_ty.trait_id().expect("trait expected")
    }
}

impl Index<ImplDefinitionId> for Vec<RwLock<ImplDefinition>> {
    type Output = RwLock<ImplDefinition>;

    fn index(&self, index: ImplDefinitionId) -> &RwLock<ImplDefinition> {
        &self[index.0 as usize]
    }
}

pub fn impl_matches(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    impl_id: ImplDefinitionId,
) -> Option<SourceTypeArray> {
    let impl_ = sa.impls[impl_id].read();
    extension_matches_ty(
        sa,
        check_ty,
        check_type_param_defs,
        impl_.extended_ty.clone(),
        &impl_.type_params,
    )
}

pub fn find_trait_impl(
    sa: &SemAnalysis,
    fct_id: FctDefinitionId,
    trait_ty: SourceType,
    object_type: SourceType,
) -> FctDefinitionId {
    debug_assert!(object_type.is_concrete_type(sa));
    let impl_id = find_impl(
        sa,
        object_type,
        &TypeParamDefinition::new(),
        trait_ty.clone(),
    )
    .expect("no impl found for generic trait method call");

    let impl_ = sa.impls[impl_id].read();
    assert_eq!(
        impl_.trait_id(),
        trait_ty.trait_id().expect("trait expected")
    );

    impl_
        .impl_for
        .get(&fct_id)
        .cloned()
        .expect("no impl method found for generic trait call")
}

pub fn implements_trait(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
) -> bool {
    match check_ty {
        SourceType::Tuple(_)
        | SourceType::Unit
        | SourceType::Trait(_, _)
        | SourceType::Lambda(_, _) => false,

        SourceType::Enum(enum_id, _) => {
            let enum_ = sa.enums[enum_id].read();
            check_impls(sa, check_ty, check_type_param_defs, trait_ty, &enum_.impls).is_some()
        }

        SourceType::Bool
        | SourceType::UInt8
        | SourceType::Char
        | SourceType::Int32
        | SourceType::Int64
        | SourceType::Float32
        | SourceType::Float64 => {
            if sa.known.traits.zero() == trait_ty.trait_id().expect("trait expected") {
                assert!(trait_ty.type_params().is_empty());
                return true;
            }

            let struct_id = check_ty
                .primitive_struct_id(sa)
                .expect("primitive expected");
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
            .is_some()
        }

        SourceType::Struct(struct_id, _) => {
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
            .is_some()
        }

        SourceType::Class(_, _) => {
            let cls_id = check_ty.cls_id().expect("class expected");
            let cls = sa.classes.idx(cls_id);
            let cls = cls.read();

            check_impls(
                sa,
                check_ty.clone(),
                check_type_param_defs,
                trait_ty,
                &cls.impls,
            )
            .is_some()
        }

        SourceType::TypeParam(tp_id) => check_type_param_defs.implements_trait(tp_id, trait_ty),

        SourceType::Error | SourceType::Ptr | SourceType::This | SourceType::Any => unreachable!(),
    }
}

pub fn find_impl(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
) -> Option<ImplDefinitionId> {
    match check_ty {
        SourceType::Tuple(_)
        | SourceType::Unit
        | SourceType::Trait(_, _)
        | SourceType::Lambda(_, _) => None,

        SourceType::Enum(enum_id, _) => {
            let enum_ = sa.enums[enum_id].read();
            check_impls(sa, check_ty, check_type_param_defs, trait_ty, &enum_.impls)
        }

        SourceType::Bool
        | SourceType::UInt8
        | SourceType::Char
        | SourceType::Int32
        | SourceType::Int64
        | SourceType::Float32
        | SourceType::Float64 => {
            let struct_id = check_ty
                .primitive_struct_id(sa)
                .expect("primitive expected");
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
        }

        SourceType::Struct(struct_id, _) => {
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
        }

        SourceType::Class(_, _) => {
            let cls_id = check_ty.cls_id().expect("class expected");
            let cls = sa.classes.idx(cls_id);
            let cls = cls.read();

            check_impls(
                sa,
                check_ty.clone(),
                check_type_param_defs,
                trait_ty,
                &cls.impls,
            )
        }

        SourceType::TypeParam(_) => unreachable!(),
        SourceType::Error | SourceType::Ptr | SourceType::This | SourceType::Any => unreachable!(),
    }
}

pub fn check_impls(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
    impls: &[ImplDefinitionId],
) -> Option<ImplDefinitionId> {
    let trait_id = trait_ty.trait_id().expect("trait expected");

    for &impl_id in impls {
        let impl_ = &sa.impls[impl_id];
        let impl_ = impl_.read();

        if impl_.trait_id() != trait_id {
            continue;
        }

        // TODO: check type params for trait as well

        if impl_matches(sa, check_ty.clone(), check_type_param_defs, impl_id).is_some() {
            return Some(impl_id);
        }
    }

    None
}
<commit_msg>prepare check_impls for trait type params<commit_after>use parking_lot::RwLock;

use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::Index;
use std::sync::Arc;

use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

use crate::language::sem_analysis::{
    extension_matches_ty, FctDefinitionId, ModuleDefinitionId, SemAnalysis, SourceFileId,
    TraitDefinitionId, TypeParamDefinition,
};
use crate::language::ty::{SourceType, SourceTypeArray};
use crate::utils::Id;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImplDefinitionId(u32);

impl Id for ImplDefinition {
    type IdType = ImplDefinitionId;

    fn id_to_usize(id: ImplDefinitionId) -> usize {
        id.0 as usize
    }

    fn usize_to_id(value: usize) -> ImplDefinitionId {
        ImplDefinitionId(value.try_into().unwrap())
    }

    fn store_id(value: &mut ImplDefinition, id: ImplDefinitionId) {
        value.id = Some(id);
    }
}

#[derive(Debug)]
pub struct ImplDefinition {
    pub id: Option<ImplDefinitionId>,
    pub file_id: SourceFileId,
    pub ast: Arc<ast::Impl>,
    pub module_id: ModuleDefinitionId,
    pub pos: Position,
    pub type_params: TypeParamDefinition,
    pub trait_ty: SourceType,
    pub extended_ty: SourceType,
    pub methods: Vec<FctDefinitionId>,
    pub instance_names: HashMap<Name, FctDefinitionId>,
    pub static_names: HashMap<Name, FctDefinitionId>,
    pub impl_for: HashMap<FctDefinitionId, FctDefinitionId>,
}

impl ImplDefinition {
    pub fn new(
        file_id: SourceFileId,
        module_id: ModuleDefinitionId,
        node: &Arc<ast::Impl>,
    ) -> ImplDefinition {
        ImplDefinition {
            id: None,
            file_id,
            ast: node.clone(),
            module_id,
            type_params: TypeParamDefinition::new_ast(&node.type_params),
            pos: node.pos,
            trait_ty: SourceType::Error,
            extended_ty: SourceType::Error,
            methods: Vec::new(),
            instance_names: HashMap::new(),
            static_names: HashMap::new(),
            impl_for: HashMap::new(),
        }
    }

    pub fn id(&self) -> ImplDefinitionId {
        self.id.expect("id missing")
    }

    pub fn trait_id(&self) -> TraitDefinitionId {
        self.trait_ty.trait_id().expect("trait expected")
    }

    pub fn trait_ty(&self) -> SourceType {
        self.trait_ty.clone()
    }
}

impl Index<ImplDefinitionId> for Vec<RwLock<ImplDefinition>> {
    type Output = RwLock<ImplDefinition>;

    fn index(&self, index: ImplDefinitionId) -> &RwLock<ImplDefinition> {
        &self[index.0 as usize]
    }
}

pub fn impl_matches(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    impl_id: ImplDefinitionId,
) -> Option<SourceTypeArray> {
    let impl_ = sa.impls[impl_id].read();
    extension_matches_ty(
        sa,
        check_ty,
        check_type_param_defs,
        impl_.extended_ty.clone(),
        &impl_.type_params,
    )
}

pub fn find_trait_impl(
    sa: &SemAnalysis,
    fct_id: FctDefinitionId,
    trait_ty: SourceType,
    object_type: SourceType,
) -> FctDefinitionId {
    debug_assert!(object_type.is_concrete_type(sa));
    let impl_id = find_impl(
        sa,
        object_type,
        &TypeParamDefinition::new(),
        trait_ty.clone(),
    )
    .expect("no impl found for generic trait method call");

    let impl_ = sa.impls[impl_id].read();
    assert_eq!(
        impl_.trait_id(),
        trait_ty.trait_id().expect("trait expected")
    );

    impl_
        .impl_for
        .get(&fct_id)
        .cloned()
        .expect("no impl method found for generic trait call")
}

pub fn implements_trait(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
) -> bool {
    match check_ty {
        SourceType::Tuple(_)
        | SourceType::Unit
        | SourceType::Trait(_, _)
        | SourceType::Lambda(_, _) => false,

        SourceType::Enum(enum_id, _) => {
            let enum_ = sa.enums[enum_id].read();
            check_impls(sa, check_ty, check_type_param_defs, trait_ty, &enum_.impls).is_some()
        }

        SourceType::Bool
        | SourceType::UInt8
        | SourceType::Char
        | SourceType::Int32
        | SourceType::Int64
        | SourceType::Float32
        | SourceType::Float64 => {
            if sa.known.traits.zero() == trait_ty.trait_id().expect("trait expected") {
                assert!(trait_ty.type_params().is_empty());
                return true;
            }

            let struct_id = check_ty
                .primitive_struct_id(sa)
                .expect("primitive expected");
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
            .is_some()
        }

        SourceType::Struct(struct_id, _) => {
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
            .is_some()
        }

        SourceType::Class(_, _) => {
            let cls_id = check_ty.cls_id().expect("class expected");
            let cls = sa.classes.idx(cls_id);
            let cls = cls.read();

            check_impls(
                sa,
                check_ty.clone(),
                check_type_param_defs,
                trait_ty,
                &cls.impls,
            )
            .is_some()
        }

        SourceType::TypeParam(tp_id) => check_type_param_defs.implements_trait(tp_id, trait_ty),

        SourceType::Error | SourceType::Ptr | SourceType::This | SourceType::Any => unreachable!(),
    }
}

pub fn find_impl(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
) -> Option<ImplDefinitionId> {
    match check_ty {
        SourceType::Tuple(_)
        | SourceType::Unit
        | SourceType::Trait(_, _)
        | SourceType::Lambda(_, _) => None,

        SourceType::Enum(enum_id, _) => {
            let enum_ = sa.enums[enum_id].read();
            check_impls(sa, check_ty, check_type_param_defs, trait_ty, &enum_.impls)
        }

        SourceType::Bool
        | SourceType::UInt8
        | SourceType::Char
        | SourceType::Int32
        | SourceType::Int64
        | SourceType::Float32
        | SourceType::Float64 => {
            let struct_id = check_ty
                .primitive_struct_id(sa)
                .expect("primitive expected");
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
        }

        SourceType::Struct(struct_id, _) => {
            let struct_ = sa.structs.idx(struct_id);
            let struct_ = struct_.read();

            check_impls(
                sa,
                check_ty,
                check_type_param_defs,
                trait_ty,
                &struct_.impls,
            )
        }

        SourceType::Class(_, _) => {
            let cls_id = check_ty.cls_id().expect("class expected");
            let cls = sa.classes.idx(cls_id);
            let cls = cls.read();

            check_impls(
                sa,
                check_ty.clone(),
                check_type_param_defs,
                trait_ty,
                &cls.impls,
            )
        }

        SourceType::TypeParam(_) => unreachable!(),
        SourceType::Error | SourceType::Ptr | SourceType::This | SourceType::Any => unreachable!(),
    }
}

pub fn check_impls(
    sa: &SemAnalysis,
    check_ty: SourceType,
    check_type_param_defs: &TypeParamDefinition,
    trait_ty: SourceType,
    impls: &[ImplDefinitionId],
) -> Option<ImplDefinitionId> {
    for &impl_id in impls {
        let impl_ = &sa.impls[impl_id];
        let impl_ = impl_.read();

        debug_assert!(impl_.trait_ty().is_concrete_type(sa));

        if impl_.trait_ty() != trait_ty {
            continue;
        }

        if impl_matches(sa, check_ty.clone(), check_type_param_defs, impl_id).is_some() {
            return Some(impl_id);
        }
    }

    None
}
<|endoftext|>


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

//! Local state for external blobs and their states.

use sodiumoxide::randombytes::{randombytes};

use std::collections::hashmap::{HashMap};
use serialize::hex::{ToHex};

use process::{Process, MsgHandler};
use sqlite3::database::{Database};

use sqlite3::cursor::{Cursor};
use sqlite3::types::{SQLITE_ROW};
use sqlite3::{open};

pub type BlobIndexProcess = Process<Msg, Reply, BlobIndex>;

#[deriving(Clone, Show)]
pub struct BlobDesc {
  pub name: Vec<u8>,
  pub id: i64,
}

pub enum Msg {
  /// Reserve an internal `BlobDesc` for a new blob.
  Reserve,

  /// Report that this blob is in the process of being committed to persistent storage. If a
  /// blob is in this state when the system starts up, it may or may not exist in the persistent
  /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
  InAir(BlobDesc),

  /// Report that this blob has been fully committed to persistent storage. We can now use its
  /// reference internally. Only committed blobs are considered "safe to use".
  CommitDone(BlobDesc),
}

pub enum Reply {
  Reserved(BlobDesc),
  CommitOK,
}

pub struct BlobIndex {
  dbh: Database,
  next_id: i64,
  reserved: HashMap<Vec<u8>, BlobDesc>,
}

impl BlobIndex {

  pub fn new(path: String) -> BlobIndex {
    let mut hi = match open(path.as_slice()) {
      Ok(dbh) => BlobIndex{
        dbh: dbh,
        next_id: -1,
        reserved: HashMap::new(),
      },
      Err(err) => fail!(err.to_string()),
    };
    hi.initialize();
    hi
  }

  #[cfg(test)]
  pub fn new_for_testing() -> BlobIndex {
    BlobIndex::new(":memory:".to_string())
  }

  fn initialize(&mut self) {
    self.exec_or_die("CREATE TABLE IF NOT EXISTS
                    blob_index (id        INTEGER PRIMARY KEY,
                                name      BLOB,
                                tag       INT)");
    self.exec_or_die("CREATE UNIQUE INDEX IF NOT EXISTS
                    BlobIndex_UniqueName ON blob_index(name)");
    self.exec_or_die("BEGIN");

    self.refresh_next_id();
  }

  fn new_blob_desc(&mut self) -> BlobDesc {
    BlobDesc{name: randombytes(24),
             id: self.next_id()}
  }

  fn exec_or_die(&mut self, sql: &str) {
    match self.dbh.exec(sql) {
      Ok(true) => (),
      Ok(false) => fail!("exec: {}", self.dbh.get_errmsg()),
      Err(msg) => fail!(format!("exec: {}, {}\nIn sql: '{}'\n",
                                msg.to_string(), self.dbh.get_errmsg(), sql))
    }
  }

  fn prepare_or_die<'a>(&'a self, sql: &str) -> Cursor<'a> {
    match self.dbh.prepare(sql, &None) {
      Ok(s)  => s,
      Err(x) => fail!(format!("sqlite error: {} ({:?})",
                              self.dbh.get_errmsg(), x)),
    }
  }

  fn select1<'a>(&'a mut self, sql: &str) -> Option<Cursor<'a>> {
    let mut cursor = self.prepare_or_die(sql);
    if cursor.step() == SQLITE_ROW {
      Some(cursor)
    } else { None }
  }

  fn refresh_next_id(&mut self) {
    let id = self.select1("SELECT MAX(id) FROM blob_index").unwrap().get_int(0);
    self.next_id = (id as i64) + 1;
  }

  fn next_id(&mut self) -> i64 {
    let id = self.next_id;
    self.next_id += 1;
    id
  }

  fn reserve(&mut self) -> BlobDesc {
    let blob = self.new_blob_desc();
    self.reserved.insert(blob.name.clone(), blob.clone());
    blob
  }

  fn in_air(&mut self, blob: &BlobDesc) {
    assert!(self.reserved.find(&blob.name).is_some(), "blob was not reserved!");
    self.exec_or_die(format!(
      "INSERT INTO blob_index (id, name, tag) VALUES ({}, x'{}', {})",
      blob.id, blob.name.as_slice().to_hex(), 1u).as_slice());
    self.new_transaction();
  }

  fn new_transaction(&mut self) {
    self.exec_or_die("COMMIT; BEGIN");
  }

  fn commit_blob(&mut self, blob: &BlobDesc) {
    assert!(self.reserved.find(&blob.name).is_some(), "blob was not reserved!");
    self.exec_or_die(format!("UPDATE blob_index SET tag=0 WHERE id={}", blob.id).as_slice());
    self.new_transaction();
  }
}

impl Drop for BlobIndex {
  fn drop(&mut self) {
    self.exec_or_die("COMMIT");
  }
}

impl MsgHandler<Msg, Reply> for BlobIndex {
  fn handle(&mut self, msg: Msg, reply: |Reply|) {
    match msg {
      Reserve => {
        return reply(Reserved(self.reserve()));
      },
      InAir(blob) => {
        self.in_air(&blob);
        return reply(CommitOK);
      },
      CommitDone(blob) => {
        self.commit_blob(&blob);
        return reply(CommitOK);
      }
    }
  }
}
<commit_msg>Minor indentation fix in SQL query.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Local state for external blobs and their states.

use sodiumoxide::randombytes::{randombytes};

use std::collections::hashmap::{HashMap};
use serialize::hex::{ToHex};

use process::{Process, MsgHandler};
use sqlite3::database::{Database};

use sqlite3::cursor::{Cursor};
use sqlite3::types::{SQLITE_ROW};
use sqlite3::{open};

pub type BlobIndexProcess = Process<Msg, Reply, BlobIndex>;

#[deriving(Clone, Show)]
pub struct BlobDesc {
  pub name: Vec<u8>,
  pub id: i64,
}

pub enum Msg {
  /// Reserve an internal `BlobDesc` for a new blob.
  Reserve,

  /// Report that this blob is in the process of being committed to persistent storage. If a
  /// blob is in this state when the system starts up, it may or may not exist in the persistent
  /// storage, but **should not** be referenced elsewhere, and is therefore safe to delete.
  InAir(BlobDesc),

  /// Report that this blob has been fully committed to persistent storage. We can now use its
  /// reference internally. Only committed blobs are considered "safe to use".
  CommitDone(BlobDesc),
}

pub enum Reply {
  Reserved(BlobDesc),
  CommitOK,
}

pub struct BlobIndex {
  dbh: Database,
  next_id: i64,
  reserved: HashMap<Vec<u8>, BlobDesc>,
}

impl BlobIndex {

  pub fn new(path: String) -> BlobIndex {
    let mut hi = match open(path.as_slice()) {
      Ok(dbh) => BlobIndex{
        dbh: dbh,
        next_id: -1,
        reserved: HashMap::new(),
      },
      Err(err) => fail!(err.to_string()),
    };
    hi.initialize();
    hi
  }

  #[cfg(test)]
  pub fn new_for_testing() -> BlobIndex {
    BlobIndex::new(":memory:".to_string())
  }

  fn initialize(&mut self) {
    self.exec_or_die("CREATE TABLE IF NOT EXISTS
                      blob_index (id        INTEGER PRIMARY KEY,
                                  name      BLOB,
                                  tag       INT)");
    self.exec_or_die("CREATE UNIQUE INDEX IF NOT EXISTS
                      BlobIndex_UniqueName ON blob_index(name)");
    self.exec_or_die("BEGIN");

    self.refresh_next_id();
  }

  fn new_blob_desc(&mut self) -> BlobDesc {
    BlobDesc{name: randombytes(24),
             id: self.next_id()}
  }

  fn exec_or_die(&mut self, sql: &str) {
    match self.dbh.exec(sql) {
      Ok(true) => (),
      Ok(false) => fail!("exec: {}", self.dbh.get_errmsg()),
      Err(msg) => fail!(format!("exec: {}, {}\nIn sql: '{}'\n",
                                msg.to_string(), self.dbh.get_errmsg(), sql))
    }
  }

  fn prepare_or_die<'a>(&'a self, sql: &str) -> Cursor<'a> {
    match self.dbh.prepare(sql, &None) {
      Ok(s)  => s,
      Err(x) => fail!(format!("sqlite error: {} ({:?})",
                              self.dbh.get_errmsg(), x)),
    }
  }

  fn select1<'a>(&'a mut self, sql: &str) -> Option<Cursor<'a>> {
    let mut cursor = self.prepare_or_die(sql);
    if cursor.step() == SQLITE_ROW {
      Some(cursor)
    } else { None }
  }

  fn refresh_next_id(&mut self) {
    let id = self.select1("SELECT MAX(id) FROM blob_index").unwrap().get_int(0);
    self.next_id = (id as i64) + 1;
  }

  fn next_id(&mut self) -> i64 {
    let id = self.next_id;
    self.next_id += 1;
    id
  }

  fn reserve(&mut self) -> BlobDesc {
    let blob = self.new_blob_desc();
    self.reserved.insert(blob.name.clone(), blob.clone());
    blob
  }

  fn in_air(&mut self, blob: &BlobDesc) {
    assert!(self.reserved.find(&blob.name).is_some(), "blob was not reserved!");
    self.exec_or_die(format!(
      "INSERT INTO blob_index (id, name, tag) VALUES ({}, x'{}', {})",
      blob.id, blob.name.as_slice().to_hex(), 1u).as_slice());
    self.new_transaction();
  }

  fn new_transaction(&mut self) {
    self.exec_or_die("COMMIT; BEGIN");
  }

  fn commit_blob(&mut self, blob: &BlobDesc) {
    assert!(self.reserved.find(&blob.name).is_some(), "blob was not reserved!");
    self.exec_or_die(format!("UPDATE blob_index SET tag=0 WHERE id={}", blob.id).as_slice());
    self.new_transaction();
  }
}

impl Drop for BlobIndex {
  fn drop(&mut self) {
    self.exec_or_die("COMMIT");
  }
}

impl MsgHandler<Msg, Reply> for BlobIndex {
  fn handle(&mut self, msg: Msg, reply: |Reply|) {
    match msg {
      Reserve => {
        return reply(Reserved(self.reserve()));
      },
      InAir(blob) => {
        self.in_air(&blob);
        return reply(CommitOK);
      },
      CommitDone(blob) => {
        self.commit_blob(&blob);
        return reply(CommitOK);
      }
    }
  }
}
<|endoftext|>


<commit_before>extern crate gunship;
extern crate rand;

use std::f32::consts::PI;

use gunship::*;

const TOTAL_CUBES: usize = 10_000;

fn main() {
    let mut engine = Engine::new();

    engine.register_system(circle_movement_update);
    setup_scene(engine.scene_mut());

    engine.main_loop();
}

fn setup_scene(scene: &mut Scene) {
    scene.register_manager(CircleMovementManager::new());

    scene.resource_manager().set_resource_path("examples/");
    scene.resource_manager().load_model("meshes/cube.dae").unwrap();

    let mut transform_manager = scene.get_manager_mut::<TransformManager>();
    let mut camera_manager = scene.get_manager_mut::<CameraManager>();
    let mut light_manager = scene.get_manager_mut::<LightManager>();
    let mut circle_movement_manager = scene.get_manager_mut::<CircleMovementManager>();
    let mut mesh_manager = scene.get_manager_mut::<MeshManager>();
    let mut collider_manager = scene.get_manager_mut::<ColliderManager>();

    // Create camera.
    {
        let camera = scene.create_entity();
        let mut camera_transform = transform_manager.assign(camera);
        camera_transform.set_position(Point::new(0.0, 0.0, 30.0));
        camera_transform.look_at(Point::origin(), Vector3::new(0.0, 0.0, -1.0));
        camera_manager.assign(
            camera,
            Camera::new(
                PI / 3.0,
                1.0,
                0.001,
                100.0));
    }

    // Create light.
    {
        let light = scene.create_entity();
        transform_manager.assign(light);
        light_manager.assign(
            light,
            Light::Point(PointLight {
                position: Point::origin()
            }));
    }

    // Create a marker at the origin.
    {
        let entity = scene.create_entity();
        let mut transform = transform_manager.assign(entity);
        transform.set_scale(Vector3::new(0.1, 0.1, 0.1));
        mesh_manager.assign(entity, "cube.pCube1");
    }

    // Create some amount of cubes.
    for _ in 0..TOTAL_CUBES {
        let entity = scene.create_entity();
        transform_manager.assign(entity);
        circle_movement_manager.assign(entity, CircleMovement::new());
        collider_manager.assign(entity, Collider::Sphere {
            offset: Vector3::zero(),
            radius: rand::random::<f32>() * 1.0 + 0.5,
        });
        collider_manager.register_callback(entity, visualize_collision);
        // mesh_manager.assign(entity, "cube.pCube1");
    }
}

#[derive(Debug, Clone)]
struct CircleMovement {
    center: Point,
    radius: f32,
    period: f32,
    offset: f32,
}

impl CircleMovement {
    fn new() -> CircleMovement {
        CircleMovement {
            center: Point::new(
                rand::random::<f32>() * 100.0 - 50.0,
                rand::random::<f32>() * 100.0 - 50.0,
                0.0),
            radius: rand::random::<f32>() * 4.0 + 1.0,
            period: rand::random::<f32>() * 1.0 + 4.0,
            offset: 0.0,
        }
    }
}

type CircleMovementManager = StructComponentManager<CircleMovement>;

fn circle_movement_update(scene: &Scene, delta: f32) {
    let circle_movement_manager = scene.get_manager::<CircleMovementManager>();
    let transform_manager = scene.get_manager::<TransformManager>();

    for (mut circle_movement, entity) in circle_movement_manager.iter_mut() {
        let mut transform = transform_manager.get_mut(entity);

        // Calculate the position of the cube.
        circle_movement.offset += delta;
        let t = circle_movement.offset * PI * 2.0 / circle_movement.period;
        let x_offset = t.cos() * circle_movement.radius;
        let y_offset = t.sin() * circle_movement.radius;

        // Move the cube.
        transform.set_position( circle_movement.center + Vector3::new( x_offset, y_offset, 0.0 ) );
    }
}

fn visualize_collision(scene: &Scene, entity: Entity, _other: Entity) {
    let transform_manager = scene.get_manager::<TransformManager>();
    let transform = transform_manager.get(entity);
    let center = transform.position() + Vector3::new(0.0, 0.0, 0.5);
    debug_draw::box_center_widths(center, Vector3::new(0.4, 0.4, 0.4));
}
<commit_msg>Improved Collision Example<commit_after>extern crate gunship;
extern crate rand;

use std::f32::consts::PI;

use gunship::*;

const TOTAL_CUBES: usize = 5_000;
const TOTAL_SPHERES: usize = 5_000;

fn main() {
    let mut engine = Engine::new();

    engine.register_system(LoopUpdate { offset: 0.0 });
    engine.register_system(rotation_update);
    engine.register_system(camera_movement);
    setup_scene(engine.scene_mut());

    engine.main_loop();
}

fn setup_scene(scene: &mut Scene) {
    scene.register_manager(LoopMovementManager::new());
    scene.register_manager(RotationManager::new());
    scene.register_manager(CameraControllerManager::new());

    scene.resource_manager().set_resource_path("examples/");
    scene.resource_manager().load_model("meshes/cube.dae").unwrap();
    // scene.resource_manager().load_model("meshes/sphere.dae").unwrap(); // TODO: Fix broken sphere mesh loading.

    let mut transform_manager = scene.get_manager_mut::<TransformManager>();
    let mut camera_manager = scene.get_manager_mut::<CameraManager>();
    let mut light_manager = scene.get_manager_mut::<LightManager>();
    let mut movement_manager = scene.get_manager_mut::<LoopMovementManager>();
    let mut rotation_manager = scene.get_manager_mut::<RotationManager>();
    let mut mesh_manager = scene.get_manager_mut::<MeshManager>();
    let mut collider_manager = scene.get_manager_mut::<ColliderManager>();
    let mut camera_controller = scene.get_manager_mut::<CameraControllerManager>();

    // Create camera.
    {
        let root = scene.create_entity();
        {
            let mut root_transform = transform_manager.assign(root);
            root_transform.set_position(Point::new(0.0, 0.0, 30.0));
            root_transform.look_at(Point::origin(), Vector3::new(0.0, 0.0, -1.0));
        }

        let camera = scene.create_entity();
        transform_manager.assign(camera);
        camera_manager.assign(
            camera,
            Camera::new(
                PI / 3.0,
                1.0,
                0.001,
                100.0));

        transform_manager.set_child(root, camera);

        camera_controller.assign(root, CameraController {
            camera: camera,
            velocity: Vector3::zero(),
        });
    }

    // Create light.
    {
        let light = scene.create_entity();
        transform_manager.assign(light).set_position(Point::new(0.0, 0.0, 5.0));
        light_manager.assign(
            light,
            Light::Point(PointLight {
                position: Point::origin()
            }));
    }

    // Create a marker at the origin.
    {
        let entity = scene.create_entity();
        let mut transform = transform_manager.assign(entity);
        transform.set_scale(Vector3::new(0.1, 0.1, 0.1));
        mesh_manager.assign(entity, "cube.pCube1");
    }

    // Create some amount of cubes.
    for _ in 0..TOTAL_CUBES {
        let entity = scene.create_entity();
        // let mut transform =
            transform_manager.assign(entity);
        // transform.set_scale(Vector3::new(
        //     random_range(0.5, 3.5),
        //     random_range(0.5, 3.5),
        //     random_range(0.5, 3.5),
        // ));
        movement_manager.assign(entity, LoopMovement {
            movement_type: MovementType::Circle,
            center: Point::new(
                random_range(-50.0, 50.0),
                random_range(-50.0, 50.0),
                0.0),
            radius: random_range(1.0, 5.0),
            period: random_range(10.0, 15.0),
        });
        collider_manager.assign(entity, Collider::Box {
            offset: Vector3::zero(),
            widths: Vector3::one(),
        });
        collider_manager.assign_callback(entity, visualize_collision);
        mesh_manager.assign(entity, "cube.pCube1");
        rotation_manager.assign(entity, RotationMovement::new(
            random_range(0.01, 0.15) * PI,
            random_range(0.01, 0.15) * PI,
            random_range(0.01, 0.15) * PI));
    }

    // Create some amount of spheres.
    for _ in 0..TOTAL_SPHERES {
        let entity = scene.create_entity();
        transform_manager.assign(entity);
        movement_manager.assign(entity, LoopMovement {
            movement_type: MovementType::Circle,
            center: Point::new(
                random_range(-50.0, 50.0),
                random_range(-50.0, 50.0),
                0.0),
            radius: random_range(1.0, 5.0),
            period: random_range(10.0, 15.0),
        });
        collider_manager.assign(entity, Collider::Sphere {
            offset: Vector3::zero(),
            radius: random_range(0.5, 1.0),
        });
        collider_manager.assign_callback(entity, visualize_collision);
        // mesh_manager.assign(entity, "sphere.pSphere1"); // TODO: Fix loading sphere mesh.
    }

    // {
    //     let entity = scene.create_entity();
    //     let mut transform = transform_manager.assign(entity);
    //     transform.rotate(Quaternion::from_eulers(0.1 * PI, 1.2 * PI, 1.0 * PI));
    //     transform.set_scale(Vector3::new(2.0, 1.0, 3.0));
    //     // movement_manager.assign(entity, LoopMovement {
    //     //     movement_type: MovementType::Horizontal,
    //     //     center: Point::origin(),
    //     //     radius: 6.0,
    //     //     period: 15.0,
    //     // });
    //     collider_manager.assign(entity, Collider::Box {
    //         offset: Vector3::zero(),
    //         widths: Vector3::new(1.0, 1.0, 1.0),
    //     });
    //     collider_manager.register_callback(entity, visualize_collision);
    //     // mesh_manager.assign(entity, "cube.pCube1");
    //     rotation_manager.assign(entity, RotationMovement::new(0.01 * PI, 0.12 * PI, 0.03 * PI));
    // }
    //
    // {
    //     let entity = scene.create_entity();
    //     let mut transform = transform_manager.assign(entity);
    //     transform.rotate(Quaternion::from_eulers(0.1 * PI, 1.2 * PI, 0.1 * PI));
    //     transform.set_scale(Vector3::new(2.0, 1.0, 3.0));
    //     movement_manager.assign(entity, LoopMovement {
    //         movement_type: MovementType::Horizontal,
    //         center: Point::origin(),
    //         radius: 6.0,
    //         period: 15.0,
    //     });
    //     collider_manager.assign(entity, Collider::Sphere {
    //         offset: Vector3::zero(),
    //         radius: 1.0,
    //     });
    //     collider_manager.register_callback(entity, visualize_collision);
    //     // mesh_manager.assign(entity, "sphere.pSphere1");
    //     // rotation_manager.assign(entity, RotationMovement::new(0.0232 * PI, 0.0 * PI, 0.01 * PI));
    // }
}

#[derive(Debug, Clone, Copy)]
enum MovementType {
    Circle,
    Vertical,
    Horizontal,
}

#[derive(Debug, Clone, Copy)]
struct LoopMovement {
    movement_type: MovementType,
    center:        Point,
    radius:        f32,
    period:        f32,
}

type LoopMovementManager = StructComponentManager<LoopMovement>;

#[derive(Debug, Clone)]
struct LoopUpdate {
    offset: f32,
}

impl System for LoopUpdate {
    fn update(&mut self, scene: &Scene, delta: f32) {
        let movement_manager = scene.get_manager::<LoopMovementManager>();
        let transform_manager = scene.get_manager::<TransformManager>();

        self.offset += delta;
        for (mut movement, entity) in movement_manager.iter_mut() {
            let mut transform = transform_manager.get_mut(entity);

            // Calculate the position of the cube.
            let t = self.offset * PI * 2.0 / movement.period;
            let x_offset = t.cos() * movement.radius;
            let y_offset = t.sin() * movement.radius;

            match movement.movement_type {
                MovementType::Circle => {
                    transform.set_position(movement.center + Vector3::new(x_offset, y_offset, 0.0));
                },
                MovementType::Horizontal => {
                    transform.set_position(movement.center + Vector3::new(x_offset, 0.0, 0.0));
                },
                MovementType::Vertical => {
                    transform.set_position(movement.center + Vector3::new(0.0, y_offset, 0.0));
                }
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
struct RotationMovement {
    x: f32,
    y: f32,
    z: f32,
}

impl RotationMovement {
    fn new(x: f32, y: f32, z: f32) -> RotationMovement {
        RotationMovement {
            x: x,
            y: y,
            z: z,
        }
    }
}

type RotationManager = StructComponentManager<RotationMovement>;

fn rotation_update(scene: &Scene, delta: f32) {
    let rotation_manager = scene.get_manager::<RotationManager>();
    let transform_manager = scene.get_manager::<TransformManager>();

    for (movement, entity) in rotation_manager.iter() {
        let mut transform = transform_manager.get_mut(entity);
        transform.rotate(Quaternion::from_eulers(movement.x * delta, movement.y * delta, movement.z * delta));
    }
}

fn visualize_collision(scene: &Scene, entity: Entity, _other: Entity) {
    // let transform_manager = scene.get_manager::<TransformManager>();
    // let transform = transform_manager.get(entity);
    // // let center = transform.position() + Vector3::new(0.0, 0.0, 0.5);
    // // debug_draw::box_center_widths(center, Vector3::new(0.4, 0.4, 0.4));
    // debug_draw::sphere(transform.position(), 1.0);
}

#[derive(Debug, Clone, Copy)]
struct CameraController {
    camera: Entity,
    velocity: Vector3,
}

type CameraControllerManager = StructComponentManager<CameraController>;

fn camera_movement(scene: &Scene, delta: f32) {
    const ACCELERATION: f32 = 50.0;
    const MAX_SPEED: f32 = 5.0;

    let player_manager = scene.get_manager::<CameraControllerManager>();
    let transform_manager = scene.get_manager::<TransformManager>();

    for (mut player, root_entity) in player_manager.iter_mut() {

            let (movement_x, movement_y) = scene.input.mouse_delta();

            // Handle movement through root entity.
            // The root entity handles all translation as well as rotation around the Y axis.
            {
                let mut transform = transform_manager.get_mut(root_entity);

                let rotation = transform.rotation();
                let mut velocity = player.velocity;

                transform.set_rotation(Quaternion::from_eulers(0.0, (-movement_x as f32) * PI * 0.001, 0.0) * rotation);

                // Calculate the forward and right vectors.
                // TODO: Directly retrieve local axis from transform without going through rotation matrix.
                let forward_dir = -transform.rotation().as_matrix4().z_part();
                let right_dir = transform.rotation().as_matrix4().x_part();

                // Move camera based on input.
                if scene.input.key_down(ScanCode::W) {
                    velocity = velocity + forward_dir * delta * ACCELERATION;
                }

                if scene.input.key_down(ScanCode::S) {
                    velocity = velocity - forward_dir * delta * ACCELERATION;
                }

                if scene.input.key_down(ScanCode::D) {
                    velocity = velocity + right_dir * delta * ACCELERATION;
                }

                if scene.input.key_down(ScanCode::A) {
                    velocity = velocity - right_dir * delta * ACCELERATION;
                }

                if scene.input.key_down(ScanCode::E) {
                    velocity = velocity + Vector3::up() * delta * ACCELERATION;
                }

                if scene.input.key_down(ScanCode::Q) {
                    velocity = velocity + Vector3::down() * delta * ACCELERATION;
                }

                // Clamp the velocity to the maximum speed.
                if velocity.magnitude() > MAX_SPEED {
                    velocity = velocity.normalized() * MAX_SPEED;
                }

                velocity = velocity * 0.9;
                player.velocity = velocity;
                transform.translate(velocity * delta);
            };

            {
                let mut camera_transform = transform_manager.get_mut(player.camera);
                let rotation = camera_transform.rotation();

                // Apply a rotation to the camera based on mouse movement.
                camera_transform.set_rotation(
                    Quaternion::from_eulers((-movement_y as f32) * PI * 0.001, 0.0, 0.0)
                  * rotation);
            }
    }
}

fn random_range(min: f32, max: f32) -> f32 {
    let range = max - min;
    rand::random::<f32>() * range + min
}
<|endoftext|>


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

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>iOS: fallout of `marker::NoCopy` removal<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>use super::method::MethodCallee;
use super::{FnCtxt, Needs, PlaceOp};

use rustc_ast::ast::Ident;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::DiagnosticMessageId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, TraitEngine};

use std::iter;

#[derive(Copy, Clone, Debug)]
enum AutoderefKind {
    Builtin,
    Overloaded,
}

pub struct Autoderef<'a, 'tcx> {
    infcx: &'a InferCtxt<'a, 'tcx>,
    body_id: hir::HirId,
    param_env: ty::ParamEnv<'tcx>,
    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
    cur_ty: Ty<'tcx>,
    obligations: Vec<traits::PredicateObligation<'tcx>>,
    at_start: bool,
    include_raw_pointers: bool,
    span: Span,
    silence_errors: bool,
    reached_recursion_limit: bool,
}

impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
    type Item = (Ty<'tcx>, usize);

    fn next(&mut self) -> Option<Self::Item> {
        let tcx = self.infcx.tcx;

        debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty);
        if self.at_start {
            self.at_start = false;
            debug!("autoderef stage #0 is {:?}", self.cur_ty);
            return Some((self.cur_ty, 0));
        }

        if self.steps.len() >= *tcx.sess.recursion_limit.get() {
            if !self.silence_errors {
                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
            }
            self.reached_recursion_limit = true;
            return None;
        }

        if self.cur_ty.is_ty_var() {
            return None;
        }

        // Otherwise, deref if type is derefable:
        let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers)
        {
            (AutoderefKind::Builtin, mt.ty)
        } else {
            let ty = self.overloaded_deref_ty(self.cur_ty)?;
            (AutoderefKind::Overloaded, ty)
        };

        if new_ty.references_error() {
            return None;
        }

        self.steps.push((self.cur_ty, kind));
        debug!(
            "autoderef stage #{:?} is {:?} from {:?}",
            self.steps.len(),
            new_ty,
            (self.cur_ty, kind)
        );
        self.cur_ty = new_ty;

        Some((self.cur_ty, self.steps.len()))
    }
}

impl<'a, 'tcx> Autoderef<'a, 'tcx> {
    pub fn new(
        infcx: &'a InferCtxt<'a, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        body_id: hir::HirId,
        span: Span,
        base_ty: Ty<'tcx>,
    ) -> Autoderef<'a, 'tcx> {
        Autoderef {
            infcx,
            body_id,
            param_env,
            steps: vec![],
            cur_ty: infcx.resolve_vars_if_possible(&base_ty),
            obligations: vec![],
            at_start: true,
            include_raw_pointers: false,
            silence_errors: false,
            reached_recursion_limit: false,
            span,
        }
    }

    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
        debug!("overloaded_deref_ty({:?})", ty);

        let tcx = self.infcx.tcx;

        // <cur_ty as Deref>
        let trait_ref = TraitRef {
            def_id: tcx.lang_items().deref_trait()?,
            substs: tcx.mk_substs_trait(self.cur_ty, &[]),
        };

        let cause = traits::ObligationCause::misc(self.span, self.body_id);

        let obligation = traits::Obligation::new(
            cause.clone(),
            self.param_env,
            trait_ref.without_const().to_predicate(),
        );
        if !self.infcx.predicate_may_hold(&obligation) {
            debug!("overloaded_deref_ty: cannot match obligation");
            return None;
        }

        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
        let normalized_ty = fulfillcx.normalize_projection_type(
            &self.infcx,
            self.param_env,
            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
            cause,
        );
        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
            // This shouldn't happen, except for evaluate/fulfill mismatches,
            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
            // by design).
            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
            return None;
        }
        let obligations = fulfillcx.pending_obligations();
        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
        self.obligations.extend(obligations);

        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
    }

    /// Returns the final type, generating an error if it is an
    /// unresolved inference variable.
    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
        fcx.structurally_resolved_type(self.span, self.cur_ty)
    }

    /// Returns the final type we ended up with, which may well be an
    /// inference variable (we will resolve it first, if possible).
    pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
        self.infcx.resolve_vars_if_possible(&self.cur_ty)
    }

    pub fn step_count(&self) -> usize {
        self.steps.len()
    }

    /// Returns the adjustment steps.
    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
    }

    pub fn adjust_steps_as_infer_ok(
        &self,
        fcx: &FnCtxt<'a, 'tcx>,
        needs: Needs,
    ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
        let mut obligations = vec![];
        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
        let steps: Vec<_> = self
            .steps
            .iter()
            .map(|&(source, kind)| {
                if let AutoderefKind::Overloaded = kind {
                    fcx.try_overloaded_deref(self.span, source, needs).and_then(
                        |InferOk { value: method, obligations: o }| {
                            obligations.extend(o);
                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
                                Some(OverloadedDeref { region, mutbl })
                            } else {
                                None
                            }
                        },
                    )
                } else {
                    None
                }
            })
            .zip(targets)
            .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
            .collect();

        InferOk { obligations, value: steps }
    }

    /// also dereference through raw pointer types
    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
    pub fn include_raw_pointers(mut self) -> Self {
        self.include_raw_pointers = true;
        self
    }

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

    pub fn reached_recursion_limit(&self) -> bool {
        self.reached_recursion_limit
    }

    pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) {
        fcx.register_predicates(self.into_obligations());
    }

    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
        self.obligations
    }
}

pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
    // We've reached the recursion limit, error gracefully.
    let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
    if fresh {
        struct_span_err!(
            tcx.sess,
            span,
            E0055,
            "reached the recursion limit while auto-dereferencing `{:?}`",
            ty
        )
        .span_label(span, "deref recursion limit reached")
        .help(&format!(
            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
            suggested_limit, tcx.crate_name,
        ))
        .emit();
    }
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
    }

    pub fn try_overloaded_deref(
        &self,
        span: Span,
        base_ty: Ty<'tcx>,
        needs: Needs,
    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
        self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
    }
}
<commit_msg>Fix wrong argument in autoderef process<commit_after>use super::method::MethodCallee;
use super::{FnCtxt, Needs, PlaceOp};

use rustc_ast::ast::Ident;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::DiagnosticMessageId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, TraitEngine};

use std::iter;

#[derive(Copy, Clone, Debug)]
enum AutoderefKind {
    Builtin,
    Overloaded,
}

pub struct Autoderef<'a, 'tcx> {
    infcx: &'a InferCtxt<'a, 'tcx>,
    body_id: hir::HirId,
    param_env: ty::ParamEnv<'tcx>,
    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
    cur_ty: Ty<'tcx>,
    obligations: Vec<traits::PredicateObligation<'tcx>>,
    at_start: bool,
    include_raw_pointers: bool,
    span: Span,
    silence_errors: bool,
    reached_recursion_limit: bool,
}

impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
    type Item = (Ty<'tcx>, usize);

    fn next(&mut self) -> Option<Self::Item> {
        let tcx = self.infcx.tcx;

        debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty);
        if self.at_start {
            self.at_start = false;
            debug!("autoderef stage #0 is {:?}", self.cur_ty);
            return Some((self.cur_ty, 0));
        }

        if self.steps.len() >= *tcx.sess.recursion_limit.get() {
            if !self.silence_errors {
                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
            }
            self.reached_recursion_limit = true;
            return None;
        }

        if self.cur_ty.is_ty_var() {
            return None;
        }

        // Otherwise, deref if type is derefable:
        let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers)
        {
            (AutoderefKind::Builtin, mt.ty)
        } else {
            let ty = self.overloaded_deref_ty(self.cur_ty)?;
            (AutoderefKind::Overloaded, ty)
        };

        if new_ty.references_error() {
            return None;
        }

        self.steps.push((self.cur_ty, kind));
        debug!(
            "autoderef stage #{:?} is {:?} from {:?}",
            self.steps.len(),
            new_ty,
            (self.cur_ty, kind)
        );
        self.cur_ty = new_ty;

        Some((self.cur_ty, self.steps.len()))
    }
}

impl<'a, 'tcx> Autoderef<'a, 'tcx> {
    pub fn new(
        infcx: &'a InferCtxt<'a, 'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        body_id: hir::HirId,
        span: Span,
        base_ty: Ty<'tcx>,
    ) -> Autoderef<'a, 'tcx> {
        Autoderef {
            infcx,
            body_id,
            param_env,
            steps: vec![],
            cur_ty: infcx.resolve_vars_if_possible(&base_ty),
            obligations: vec![],
            at_start: true,
            include_raw_pointers: false,
            silence_errors: false,
            reached_recursion_limit: false,
            span,
        }
    }

    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
        debug!("overloaded_deref_ty({:?})", ty);

        let tcx = self.infcx.tcx;

        // <ty as Deref>
        let trait_ref = TraitRef {
            def_id: tcx.lang_items().deref_trait()?,
            substs: tcx.mk_substs_trait(ty, &[]),
        };

        let cause = traits::ObligationCause::misc(self.span, self.body_id);

        let obligation = traits::Obligation::new(
            cause.clone(),
            self.param_env,
            trait_ref.without_const().to_predicate(),
        );
        if !self.infcx.predicate_may_hold(&obligation) {
            debug!("overloaded_deref_ty: cannot match obligation");
            return None;
        }

        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
        let normalized_ty = fulfillcx.normalize_projection_type(
            &self.infcx,
            self.param_env,
            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
            cause,
        );
        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
            // This shouldn't happen, except for evaluate/fulfill mismatches,
            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
            // by design).
            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
            return None;
        }
        let obligations = fulfillcx.pending_obligations();
        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
        self.obligations.extend(obligations);

        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
    }

    /// Returns the final type, generating an error if it is an
    /// unresolved inference variable.
    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
        fcx.structurally_resolved_type(self.span, self.cur_ty)
    }

    /// Returns the final type we ended up with, which may well be an
    /// inference variable (we will resolve it first, if possible).
    pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
        self.infcx.resolve_vars_if_possible(&self.cur_ty)
    }

    pub fn step_count(&self) -> usize {
        self.steps.len()
    }

    /// Returns the adjustment steps.
    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
    }

    pub fn adjust_steps_as_infer_ok(
        &self,
        fcx: &FnCtxt<'a, 'tcx>,
        needs: Needs,
    ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
        let mut obligations = vec![];
        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
        let steps: Vec<_> = self
            .steps
            .iter()
            .map(|&(source, kind)| {
                if let AutoderefKind::Overloaded = kind {
                    fcx.try_overloaded_deref(self.span, source, needs).and_then(
                        |InferOk { value: method, obligations: o }| {
                            obligations.extend(o);
                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
                                Some(OverloadedDeref { region, mutbl })
                            } else {
                                None
                            }
                        },
                    )
                } else {
                    None
                }
            })
            .zip(targets)
            .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
            .collect();

        InferOk { obligations, value: steps }
    }

    /// also dereference through raw pointer types
    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
    pub fn include_raw_pointers(mut self) -> Self {
        self.include_raw_pointers = true;
        self
    }

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

    pub fn reached_recursion_limit(&self) -> bool {
        self.reached_recursion_limit
    }

    pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) {
        fcx.register_predicates(self.into_obligations());
    }

    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
        self.obligations
    }
}

pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
    // We've reached the recursion limit, error gracefully.
    let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
    if fresh {
        struct_span_err!(
            tcx.sess,
            span,
            E0055,
            "reached the recursion limit while auto-dereferencing `{:?}`",
            ty
        )
        .span_label(span, "deref recursion limit reached")
        .help(&format!(
            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
            suggested_limit, tcx.crate_name,
        ))
        .emit();
    }
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
    }

    pub fn try_overloaded_deref(
        &self,
        span: Span,
        base_ty: Ty<'tcx>,
        needs: Needs,
    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
        self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
    }
}
<|endoftext|>