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

use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use std::fmt::Write;
use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax::symbol::{Symbol, InternedString};
use ty::TyCtxt;
use util::nodemap::NodeMap;

//! For each definition, we track the following data.  A definition
//! here is defined somewhat circularly as "something with a def-id",
//! but it generally corresponds to things like structs, enums, etc.
//! There are also some rather random cases (like const initializer
//! expressions) that are mostly just leftovers.

/// The definition table containing node definitions
#[derive(Clone)]
pub struct Definitions {
    data: Vec<DefKey>,
    key_map: FxHashMap<DefKey, DefIndex>,
    node_to_def_index: NodeMap<DefIndex>,
    def_index_to_node: Vec<ast::NodeId>,
}

/// A unique identifier that we can use to lookup a definition
/// precisely. It combines the index of the definition's parent (if
/// any) with a `DisambiguatedDefPathData`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DefKey {
    /// Parent path.
    pub parent: Option<DefIndex>,

    /// Identifier of this node.
    pub disambiguated_data: DisambiguatedDefPathData,
}

/// Pair of `DefPathData` and an integer disambiguator. The integer is
/// normally 0, but in the event that there are multiple defs with the
/// same `parent` and `data`, we use this field to disambiguate
/// between them. This introduces some artificial ordering dependency
/// but means that if you have (e.g.) two impls for the same type in
/// the same module, they do get distinct def-ids.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DisambiguatedDefPathData {
    pub data: DefPathData,
    pub disambiguator: u32
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DefPath {
    /// the path leading from the crate root to the item
    pub data: Vec<DisambiguatedDefPathData>,

    /// what krate root is this path relative to?
    pub krate: CrateNum,
}

impl DefPath {
    pub fn is_local(&self) -> bool {
        self.krate == LOCAL_CRATE
    }

    pub fn make<FN>(start_krate: CrateNum,
                    start_index: DefIndex,
                    mut get_key: FN) -> DefPath
        where FN: FnMut(DefIndex) -> DefKey
    {
        let mut krate = start_krate;
        let mut data = vec![];
        let mut index = Some(start_index);
        loop {
            debug!("DefPath::make: krate={:?} index={:?}", krate, index);
            let p = index.unwrap();
            let key = get_key(p);
            debug!("DefPath::make: key={:?}", key);
            match key.disambiguated_data.data {
                DefPathData::CrateRoot => {
                    assert!(key.parent.is_none());
                    break;
                }
                DefPathData::InlinedRoot(ref p) => {
                    assert!(key.parent.is_none());
                    assert!(!p.def_id.is_local());
                    data.extend(p.data.iter().cloned().rev());
                    krate = p.def_id.krate;
                    break;
                }
                _ => {
                    data.push(key.disambiguated_data);
                    index = key.parent;
                }
            }
        }
        data.reverse();
        DefPath { data: data, krate: krate }
    }

    pub fn to_string(&self, tcx: TyCtxt) -> String {
        let mut s = String::with_capacity(self.data.len() * 16);

        s.push_str(&tcx.original_crate_name(self.krate).as_str());
        s.push_str("/");
        s.push_str(&tcx.crate_disambiguator(self.krate).as_str());

        for component in &self.data {
            write!(s,
                   "::{}[{}]",
                   component.data.as_interned_str(),
                   component.disambiguator)
                .unwrap();
        }

        s
    }

    pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
        debug!("deterministic_hash({:?})", self);
        let mut state = StableHasher::new();
        self.deterministic_hash_to(tcx, &mut state);
        state.finish()
    }

    pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
        tcx.original_crate_name(self.krate).as_str().hash(state);
        tcx.crate_disambiguator(self.krate).as_str().hash(state);
        self.data.hash(state);
    }
}

/// Root of an inlined item. We track the `DefPath` of the item within
/// the original crate but also its def-id. This is kind of an
/// augmented version of a `DefPath` that includes a `DefId`. This is
/// all sort of ugly but the hope is that inlined items will be going
/// away soon anyway.
///
/// Some of the constraints that led to the current approach:
///
/// - I don't want to have a `DefId` in the main `DefPath` because
///   that gets serialized for incr. comp., and when reloaded the
///   `DefId` is no longer valid. I'd rather maintain the invariant
///   that every `DefId` is valid, and a potentially outdated `DefId` is
///   represented as a `DefPath`.
///   - (We don't serialize def-paths from inlined items, so it's ok to have one here.)
/// - We need to be able to extract the def-id from inline items to
///   make the symbol name. In theory we could retrace it from the
///   data, but the metadata doesn't have the required indices, and I
///   don't want to write the code to create one just for this.
/// - It may be that we don't actually need `data` at all. We'll have
///   to see about that.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct InlinedRootPath {
    pub data: Vec<DisambiguatedDefPathData>,
    pub def_id: DefId,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
    // Root: these should only be used for the root nodes, because
    // they are treated specially by the `def_path` function.
    /// The crate root (marker)
    CrateRoot,
    /// An inlined root
    InlinedRoot(Box<InlinedRootPath>),

    // Catch-all for random DefId things like DUMMY_NODE_ID
    Misc,

    // Different kinds of items and item-like things:
    /// An impl
    Impl,
    /// Something in the type NS
    TypeNs(InternedString),
    /// Something in the value NS
    ValueNs(InternedString),
    /// A module declaration
    Module(InternedString),
    /// A macro rule
    MacroDef(InternedString),
    /// A closure expression
    ClosureExpr,

    // Subportions of items
    /// A type parameter (generic parameter)
    TypeParam(InternedString),
    /// A lifetime definition
    LifetimeDef(InternedString),
    /// A variant of a enum
    EnumVariant(InternedString),
    /// A struct field
    Field(InternedString),
    /// Implicit ctor for a tuple-like struct
    StructCtor,
    /// Initializer for a const
    Initializer,
    /// Pattern binding
    Binding(InternedString),
    /// An `impl Trait` type node.
    ImplTrait
}

impl Definitions {
    /// Create new empty definition map.
    pub fn new() -> Definitions {
        Definitions {
            data: vec![],
            key_map: FxHashMap(),
            node_to_def_index: NodeMap(),
            def_index_to_node: vec![],
        }
    }

    /// Get the number of definitions.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn def_key(&self, index: DefIndex) -> DefKey {
        self.data[index.as_usize()].key.clone()
    }

    pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
        self.key_map.get(&key).cloned()
    }

    /// Returns the path from the crate root to `index`. The root
    /// nodes are not included in the path (i.e., this will be an
    /// empty vector for the crate root). For an inlined item, this
    /// will be the path of the item in the external crate (but the
    /// path will begin with the path to the external crate).
    pub fn def_path(&self, index: DefIndex) -> DefPath {
        DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p))
    }

    pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
        self.node_to_def_index.get(&node).cloned()
    }

    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
        self.opt_def_index(node).map(DefId::local)
    }

    pub fn local_def_id(&self, node: ast::NodeId) -> DefId {
        self.opt_local_def_id(node).unwrap()
    }

    pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
        if def_id.krate == LOCAL_CRATE {
            assert!(def_id.index.as_usize() < self.data.len());
            // Some(self.data[def_id.index.as_usize()].node_id)
            Some(self.def_index_to_node[def_id.index.as_usize()])
        } else {
            None
        }
    }

    /// Add a definition with a parent definition.
    pub fn create_def_with_parent(&mut self,
                                  parent: Option<DefIndex>,
                                  node_id: ast::NodeId,
                                  data: DefPathData)
                                  -> DefIndex {
        debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
               parent, node_id, data);

        assert!(!self.node_to_def_index.contains_key(&node_id),
                "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
                node_id,
                data,
                self.data[self.node_to_def_index[&node_id].as_usize()]);

        assert!(parent.is_some() ^ match data {
            DefPathData::CrateRoot | DefPathData::InlinedRoot(_) => true,
            _ => false,
        });

        // Find a unique DefKey. This basically means incrementing the disambiguator
        // until we get no match.
        let mut key = DefKey {
            parent: parent,
            disambiguated_data: DisambiguatedDefPathData {
                data: data,
                disambiguator: 0
            }
        };

        while self.key_map.contains_key(&key) {
            key.disambiguated_data.disambiguator += 1;
        }

        debug!("create_def_with_parent: after disambiguation, key = {:?}", key);

        // Create the definition.
        let index = DefIndex::new(self.data.len());
        self.data.push(DefData { key: key.clone() });
        self.def_index_to_node.push(node_id);
        debug!("create_def_with_parent: node_to_def_index[{:?}] = {:?}", node_id, index);
        self.node_to_def_index.insert(node_id, index);
        debug!("create_def_with_parent: key_map[{:?}] = {:?}", key, index);
        self.key_map.insert(key, index);

        index
    }
}

impl DefPathData {
    pub fn get_opt_name(&self) -> Option<ast::Name> {
        use self::DefPathData::*;
        match *self {
            TypeNs(ref name) |
            ValueNs(ref name) |
            Module(ref name) |
            MacroDef(ref name) |
            TypeParam(ref name) |
            LifetimeDef(ref name) |
            EnumVariant(ref name) |
            Binding(ref name) |
            Field(ref name) => Some(Symbol::intern(name)),

            Impl |
            CrateRoot |
            InlinedRoot(_) |
            Misc |
            ClosureExpr |
            StructCtor |
            Initializer |
            ImplTrait => None
        }
    }

    pub fn as_interned_str(&self) -> InternedString {
        use self::DefPathData::*;
        let s = match *self {
            TypeNs(ref name) |
            ValueNs(ref name) |
            Module(ref name) |
            MacroDef(ref name) |
            TypeParam(ref name) |
            LifetimeDef(ref name) |
            EnumVariant(ref name) |
            Binding(ref name) |
            Field(ref name) => {
                return name.clone();
            }

            // note that this does not show up in user printouts
            CrateRoot => "{{root}}",

            // note that this does not show up in user printouts
            InlinedRoot(_) => "{{inlined-root}}",

            Impl => "{{impl}}",
            Misc => "{{?}}",
            ClosureExpr => "{{closure}}",
            StructCtor => "{{constructor}}",
            Initializer => "{{initializer}}",
            ImplTrait => "{{impl-Trait}}",
        };

        Symbol::intern(s).as_str()
    }

    pub fn to_string(&self) -> String {
        self.as_interned_str().to_string()
    }
}
<commit_msg>Definitions: Extract DefPath interning into its own data structure.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! For each definition, we track the following data.  A definition
//! here is defined somewhat circularly as "something with a def-id",
//! but it generally corresponds to things like structs, enums, etc.
//! There are also some rather random cases (like const initializer
//! expressions) that are mostly just leftovers.

use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use serialize::{Encodable, Decodable, Encoder, Decoder};
use std::fmt::Write;
use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax::symbol::{Symbol, InternedString};
use ty::TyCtxt;
use util::nodemap::NodeMap;

#[derive(Clone)]
pub struct DefPathTable {
    index_to_key: Vec<DefKey>,
    key_to_index: FxHashMap<DefKey, DefIndex>,
}

impl DefPathTable {
    fn insert(&mut self, key: DefKey) -> DefIndex {
        let index = DefIndex::new(self.index_to_key.len());
        debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
        self.index_to_key.push(key.clone());
        self.key_to_index.insert(key, index);
        index
    }

    #[inline(always)]
    pub fn def_key(&self, index: DefIndex) -> DefKey {
        self.index_to_key[index.as_usize()].clone()
    }

    #[inline(always)]
    pub fn def_index_for_def_key(&self, key: &DefKey) -> Option<DefIndex> {
        self.key_to_index.get(key).cloned()
    }

    #[inline(always)]
    pub fn contains_key(&self, key: &DefKey) -> bool {
        self.key_to_index.contains_key(key)
    }

    /// Returns the path from the crate root to `index`. The root
    /// nodes are not included in the path (i.e., this will be an
    /// empty vector for the crate root). For an inlined item, this
    /// will be the path of the item in the external crate (but the
    /// path will begin with the path to the external crate).
    pub fn def_path(&self, index: DefIndex) -> DefPath {
        DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p))
    }
}

impl Encodable for DefPathTable {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.index_to_key.encode(s)
    }
}

impl Decodable for DefPathTable {
    fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
        let index_to_key: Vec<DefKey> = Decodable::decode(d)?;
        let key_to_index = index_to_key.iter()
                                       .enumerate()
                                       .map(|(index, key)| (key.clone(), DefIndex::new(index)))
                                       .collect();
        Ok(DefPathTable {
            index_to_key: index_to_key,
            key_to_index: key_to_index,
        })
    }
}

/// The definition table containing node definitions
#[derive(Clone)]
pub struct Definitions {
    table: DefPathTable,
    node_to_def_index: NodeMap<DefIndex>,
    def_index_to_node: Vec<ast::NodeId>,
}

/// A unique identifier that we can use to lookup a definition
/// precisely. It combines the index of the definition's parent (if
/// any) with a `DisambiguatedDefPathData`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DefKey {
    /// Parent path.
    pub parent: Option<DefIndex>,

    /// Identifier of this node.
    pub disambiguated_data: DisambiguatedDefPathData,
}

/// Pair of `DefPathData` and an integer disambiguator. The integer is
/// normally 0, but in the event that there are multiple defs with the
/// same `parent` and `data`, we use this field to disambiguate
/// between them. This introduces some artificial ordering dependency
/// but means that if you have (e.g.) two impls for the same type in
/// the same module, they do get distinct def-ids.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DisambiguatedDefPathData {
    pub data: DefPathData,
    pub disambiguator: u32
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DefPath {
    /// the path leading from the crate root to the item
    pub data: Vec<DisambiguatedDefPathData>,

    /// what krate root is this path relative to?
    pub krate: CrateNum,
}

impl DefPath {
    pub fn is_local(&self) -> bool {
        self.krate == LOCAL_CRATE
    }

    pub fn make<FN>(start_krate: CrateNum,
                    start_index: DefIndex,
                    mut get_key: FN) -> DefPath
        where FN: FnMut(DefIndex) -> DefKey
    {
        let mut krate = start_krate;
        let mut data = vec![];
        let mut index = Some(start_index);
        loop {
            debug!("DefPath::make: krate={:?} index={:?}", krate, index);
            let p = index.unwrap();
            let key = get_key(p);
            debug!("DefPath::make: key={:?}", key);
            match key.disambiguated_data.data {
                DefPathData::CrateRoot => {
                    assert!(key.parent.is_none());
                    break;
                }
                DefPathData::InlinedRoot(ref p) => {
                    assert!(key.parent.is_none());
                    assert!(!p.def_id.is_local());
                    data.extend(p.data.iter().cloned().rev());
                    krate = p.def_id.krate;
                    break;
                }
                _ => {
                    data.push(key.disambiguated_data);
                    index = key.parent;
                }
            }
        }
        data.reverse();
        DefPath { data: data, krate: krate }
    }

    pub fn to_string(&self, tcx: TyCtxt) -> String {
        let mut s = String::with_capacity(self.data.len() * 16);

        s.push_str(&tcx.original_crate_name(self.krate).as_str());
        s.push_str("/");
        s.push_str(&tcx.crate_disambiguator(self.krate).as_str());

        for component in &self.data {
            write!(s,
                   "::{}[{}]",
                   component.data.as_interned_str(),
                   component.disambiguator)
                .unwrap();
        }

        s
    }

    pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
        debug!("deterministic_hash({:?})", self);
        let mut state = StableHasher::new();
        self.deterministic_hash_to(tcx, &mut state);
        state.finish()
    }

    pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
        tcx.original_crate_name(self.krate).as_str().hash(state);
        tcx.crate_disambiguator(self.krate).as_str().hash(state);
        self.data.hash(state);
    }
}

/// Root of an inlined item. We track the `DefPath` of the item within
/// the original crate but also its def-id. This is kind of an
/// augmented version of a `DefPath` that includes a `DefId`. This is
/// all sort of ugly but the hope is that inlined items will be going
/// away soon anyway.
///
/// Some of the constraints that led to the current approach:
///
/// - I don't want to have a `DefId` in the main `DefPath` because
///   that gets serialized for incr. comp., and when reloaded the
///   `DefId` is no longer valid. I'd rather maintain the invariant
///   that every `DefId` is valid, and a potentially outdated `DefId` is
///   represented as a `DefPath`.
///   - (We don't serialize def-paths from inlined items, so it's ok to have one here.)
/// - We need to be able to extract the def-id from inline items to
///   make the symbol name. In theory we could retrace it from the
///   data, but the metadata doesn't have the required indices, and I
///   don't want to write the code to create one just for this.
/// - It may be that we don't actually need `data` at all. We'll have
///   to see about that.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct InlinedRootPath {
    pub data: Vec<DisambiguatedDefPathData>,
    pub def_id: DefId,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
    // Root: these should only be used for the root nodes, because
    // they are treated specially by the `def_path` function.
    /// The crate root (marker)
    CrateRoot,
    /// An inlined root
    InlinedRoot(Box<InlinedRootPath>),

    // Catch-all for random DefId things like DUMMY_NODE_ID
    Misc,

    // Different kinds of items and item-like things:
    /// An impl
    Impl,
    /// Something in the type NS
    TypeNs(InternedString),
    /// Something in the value NS
    ValueNs(InternedString),
    /// A module declaration
    Module(InternedString),
    /// A macro rule
    MacroDef(InternedString),
    /// A closure expression
    ClosureExpr,

    // Subportions of items
    /// A type parameter (generic parameter)
    TypeParam(InternedString),
    /// A lifetime definition
    LifetimeDef(InternedString),
    /// A variant of a enum
    EnumVariant(InternedString),
    /// A struct field
    Field(InternedString),
    /// Implicit ctor for a tuple-like struct
    StructCtor,
    /// Initializer for a const
    Initializer,
    /// Pattern binding
    Binding(InternedString),
    /// An `impl Trait` type node.
    ImplTrait
}

impl Definitions {
    /// Create new empty definition map.
    pub fn new() -> Definitions {
        Definitions {
            table: DefPathTable {
                index_to_key: vec![],
                key_to_index: FxHashMap(),
            },
            node_to_def_index: NodeMap(),
            def_index_to_node: vec![],
        }
    }

    /// Get the number of definitions.
    pub fn len(&self) -> usize {
        self.def_index_to_node.len()
    }

    pub fn def_key(&self, index: DefIndex) -> DefKey {
        self.table.def_key(index)
    }

    pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
        self.table.def_index_for_def_key(&key)
    }

    /// Returns the path from the crate root to `index`. The root
    /// nodes are not included in the path (i.e., this will be an
    /// empty vector for the crate root). For an inlined item, this
    /// will be the path of the item in the external crate (but the
    /// path will begin with the path to the external crate).
    pub fn def_path(&self, index: DefIndex) -> DefPath {
        DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p))
    }

    pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
        self.node_to_def_index.get(&node).cloned()
    }

    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
        self.opt_def_index(node).map(DefId::local)
    }

    pub fn local_def_id(&self, node: ast::NodeId) -> DefId {
        self.opt_local_def_id(node).unwrap()
    }

    pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
        if def_id.krate == LOCAL_CRATE {
            assert!(def_id.index.as_usize() < self.def_index_to_node.len());
            Some(self.def_index_to_node[def_id.index.as_usize()])
        } else {
            None
        }
    }

    /// Add a definition with a parent definition.
    pub fn create_def_with_parent(&mut self,
                                  parent: Option<DefIndex>,
                                  node_id: ast::NodeId,
                                  data: DefPathData)
                                  -> DefIndex {
        debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
               parent, node_id, data);

        assert!(!self.node_to_def_index.contains_key(&node_id),
                "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
                node_id,
                data,
                self.table.def_key(self.node_to_def_index[&node_id]));

        assert!(parent.is_some() ^ match data {
            DefPathData::CrateRoot | DefPathData::InlinedRoot(_) => true,
            _ => false,
        });

        // Find a unique DefKey. This basically means incrementing the disambiguator
        // until we get no match.
        let mut key = DefKey {
            parent: parent,
            disambiguated_data: DisambiguatedDefPathData {
                data: data,
                disambiguator: 0
            }
        };

        while self.table.contains_key(&key) {
            key.disambiguated_data.disambiguator += 1;
        }

        debug!("create_def_with_parent: after disambiguation, key = {:?}", key);

        // Create the definition.
        let index = self.table.insert(key);
        debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id);
        self.node_to_def_index.insert(node_id, index);
        assert_eq!(index.as_usize(), self.def_index_to_node.len());
        self.def_index_to_node.push(node_id);

        index
    }
}

impl DefPathData {
    pub fn get_opt_name(&self) -> Option<ast::Name> {
        use self::DefPathData::*;
        match *self {
            TypeNs(ref name) |
            ValueNs(ref name) |
            Module(ref name) |
            MacroDef(ref name) |
            TypeParam(ref name) |
            LifetimeDef(ref name) |
            EnumVariant(ref name) |
            Binding(ref name) |
            Field(ref name) => Some(Symbol::intern(name)),

            Impl |
            CrateRoot |
            InlinedRoot(_) |
            Misc |
            ClosureExpr |
            StructCtor |
            Initializer |
            ImplTrait => None
        }
    }

    pub fn as_interned_str(&self) -> InternedString {
        use self::DefPathData::*;
        let s = match *self {
            TypeNs(ref name) |
            ValueNs(ref name) |
            Module(ref name) |
            MacroDef(ref name) |
            TypeParam(ref name) |
            LifetimeDef(ref name) |
            EnumVariant(ref name) |
            Binding(ref name) |
            Field(ref name) => {
                return name.clone();
            }

            // note that this does not show up in user printouts
            CrateRoot => "{{root}}",

            // note that this does not show up in user printouts
            InlinedRoot(_) => "{{inlined-root}}",

            Impl => "{{impl}}",
            Misc => "{{?}}",
            ClosureExpr => "{{closure}}",
            StructCtor => "{{constructor}}",
            Initializer => "{{initializer}}",
            ImplTrait => "{{impl-Trait}}",
        };

        Symbol::intern(s).as_str()
    }

    pub fn to_string(&self) -> String {
        self.as_interned_str().to_string()
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt::Debug;

#[derive(Debug, Clone)]
pub struct Map<K,V> {
    max_adjacent_chunks: usize,
    chunks: Vec<Chunk<K,V>>,
}

#[derive(Debug, Clone)]
struct Chunk<K,V> {
    size: usize,
    items: Vec<(K, V)>,
}

pub trait Monoid {
    fn zero() -> Self;
    fn add(v1: Self, v2: Self) -> Self;
}

fn merge<K: Ord + Debug, V: Eq + Monoid + Debug>(a: Chunk<K,V>, b: Chunk<K,V>) -> Chunk<K,V> {
    // TODO just use ixes and replace instead? or dump into vec and then merge?
    let size = a.size + b.size;
    let mut items = Vec::with_capacity(size);
    let mut a_iter = a.items.into_iter();
    let mut b_iter = b.items.into_iter();
    let mut a_next = a_iter.next();
    let mut b_next = b_iter.next();
    loop {
        let cmp = {
            match (&a_next, &b_next) {
                (&Some((ref ka, _)), &Some((ref kb, _))) => ka.cmp(kb),
                _ => break,
            }
        };
        match cmp {
            Ordering::Less => {
                let (ka, va) = ::std::mem::replace(&mut a_next, a_iter.next()).unwrap();
                items.push((ka,va));
            }
            Ordering::Equal => {
                let (ka, va) = ::std::mem::replace(&mut a_next, a_iter.next()).unwrap();
                let (_kb, vb) = ::std::mem::replace(&mut b_next, b_iter.next()).unwrap();
                let v = Monoid::add(va, vb);
                if (v != Monoid::zero()) {
                    items.push((ka, v));
                }
            }
            Ordering::Greater => {
                let (kb, vb) = ::std::mem::replace(&mut b_next, b_iter.next()).unwrap();
                items.push((kb,vb));
            }
        }
    }
    match a_next {
        Some((ka, va)) => items.push((ka, va)),
        None => (),
    }
    match b_next {
        Some((kb, vb)) => items.push((kb, vb)),
        None => (),
    }
    for (k,v) in a_iter {
        items.push((k,v));
    }
    for (k,v) in b_iter {
        items.push((k,v));
    }
    Chunk{size: size, items: items} // TODO size should be next power of two >= items.len()
}

impl<K: Ord + Debug, V: Eq + Monoid + Debug> Map<K,V> {
    pub fn new(max_adjacent_chunks: usize) -> Self {
        Map{
            max_adjacent_chunks: max_adjacent_chunks,
            chunks: vec![],
        }
    }

    pub fn insert(&mut self, key: K, val: V) {
        if val != Monoid::zero() {
            self.chunks.push(Chunk{size: 1, items: vec![(key, val)]});
            for i in (self.max_adjacent_chunks..self.chunks.len()).rev() {
                // if there are more than self.max_adjacent_chunks with the same size, merge two of them
                if self.chunks[i].size == self.chunks[i-self.max_adjacent_chunks].size {
                    let right = self.chunks.remove(i-self.max_adjacent_chunks+1);
                    let left = self.chunks.remove(i-self.max_adjacent_chunks);
                    self.chunks.insert(i-self.max_adjacent_chunks, merge(left, right));
                }
            }
        }
    }
}

impl Monoid for i64 {
    fn zero() -> i64 { 0 }
    fn add(a: i64, b: i64) -> i64 { a + b }
}<commit_msg>Simplify merge<commit_after>use std::cmp::Ordering;
use std::fmt::Debug;

#[derive(Debug, Clone)]
pub struct Map<K,V> {
    max_adjacent_chunks: usize,
    chunks: Vec<Chunk<K,V>>,
}

#[derive(Debug, Clone)]
struct Chunk<K,V> {
    size: usize,
    items: Vec<(K, V)>,
}

pub trait Monoid {
    fn zero() -> Self;
    fn add(v1: Self, v2: Self) -> Self;
}

fn merge<K: Ord + Debug, V: Eq + Monoid + Debug>(a: Chunk<K,V>, b: Chunk<K,V>) -> Chunk<K,V> {
    // TODO just use ixes and replace instead? or dump into vec and then merge?
    assert!(a.size > 0);
    assert!(b.size > 0);
    let size = a.size + b.size;
    let mut items = Vec::with_capacity(size);
    let mut active_iter = a.items.into_iter();
    let mut waiting_iter = b.items.into_iter();
    let (mut pivot_k, mut pivot_v) = waiting_iter.next().unwrap(); // we have at least one item
    // invariant: pivot is always smaller than anything in waiting_iter
    loop {
        match active_iter.next() {
            None => {
                items.push((pivot_k, pivot_v));
                for (k, v) in waiting_iter {
                    items.push((k, v))
                }
                break;
            }
            Some((mut k, mut v)) => {
                match k.cmp(&pivot_k) {
                    Ordering::Less => {
                        items.push((k,v));
                    }
                    Ordering::Equal => {
                        pivot_v = Monoid::add(v, pivot_v);
                    }
                    Ordering::Greater => {
                        ::std::mem::swap(&mut k, &mut pivot_k);
                        ::std::mem::swap(&mut v, &mut pivot_v);
                        ::std::mem::swap(&mut active_iter, &mut waiting_iter);
                        items.push((k,v));
                    }
                }
            }
        }
    }
    Chunk{size: size, items: items} // TODO size should be next power of two >= items.len()
}

impl<K: Ord + Debug, V: Eq + Monoid + Debug> Map<K,V> {
    pub fn new(max_adjacent_chunks: usize) -> Self {
        Map{
            max_adjacent_chunks: max_adjacent_chunks,
            chunks: vec![],
        }
    }

    pub fn insert(&mut self, key: K, val: V) {
        if val != Monoid::zero() {
            self.chunks.push(Chunk{size: 1, items: vec![(key, val)]});
            for i in (self.max_adjacent_chunks..self.chunks.len()).rev() {
                // if there are more than self.max_adjacent_chunks with the same size, merge two of them
                if self.chunks[i].size == self.chunks[i-self.max_adjacent_chunks].size {
                    let right = self.chunks.remove(i-self.max_adjacent_chunks+1);
                    let left = self.chunks.remove(i-self.max_adjacent_chunks);
                    self.chunks.insert(i-self.max_adjacent_chunks, merge(left, right));
                }
            }
        }
    }
}

impl Monoid for i64 {
    fn zero() -> i64 { 0 }
    fn add(a: i64, b: i64) -> i64 { a + b }
}<|endoftext|>


<commit_before>use crate::util;
use anyhow::{bail, Result};
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use validator::Validate;

#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, Validate)]
pub struct Config {
    #[serde(default)]
    #[validate]
    pub logging: crate::logging::config::Config,

    #[serde(default)]
    #[validate]
    pub serve: crate::serve::config::Config,

    #[serde(default)]
    #[validate]
    pub plugins: crate::plugins::config::Config,

    #[serde(default)]
    #[validate]
    pub upgrade: crate::upgrade::config::Config,
}

const CONFIG_FILE: &str = "config.toml";

/// Get the path of the configuration file
#[tracing::instrument]
fn path() -> Result<PathBuf> {
    #[cfg(not(test))]
    return Ok(util::dirs::config(true)?.join(CONFIG_FILE));

    // When running tests, avoid messing with users existing config
    #[cfg(test)]
    {
        let path = std::env::temp_dir()
            .join("stencila")
            .join("test")
            .join(CONFIG_FILE);
        fs::create_dir_all(path.parent().unwrap())?;
        Ok(path)
    }
}

/// Read a config from the configuration file
#[tracing::instrument]
pub fn read() -> Result<Config> {
    let config_file = path()?;

    let content = if config_file.exists() {
        match fs::read_to_string(config_file.clone()) {
            Ok(content) => content,
            // If there was a problem reading the config file warn the user
            // but return an empty string.
            Err(error) => {
                tracing::warn!("Error while reading config file: {}", error.to_string());
                String::new()
            }
        }
    } else {
        // If there is no config file just return an empty string
        String::new()
    };

    let config = match toml::from_str(content.as_str()) {
        Ok(config) => config,
        // If there was a problem reading the config file. e.g syntax error, a change
        // in the enum variants for an option, then warn the user and return the
        // defaults instead. This avoids a "corrupt" config file from preventing the
        // user from doing anything.
        Err(error) => {
            tracing::warn!(
                "Error while parsing config file; use `stencila config reset all` or edit {} to fix; defaults will be used: {}",
                config_file.display(),
                error.to_string()
            );
            Config {
                ..Default::default()
            }
        }
    };

    if let Err(errors) = config.validate() {
        tracing::error!(
            "Invalid config file; use `stencila config set`, `stencila config reset` or edit {} to fix.\n\n{}",
            config_file.display(),
            serde_json::to_string_pretty(&errors)?
        )
    }

    Ok(config)
}

/// Write a config to the configuration file
#[tracing::instrument]
fn write(config: &Config) -> Result<()> {
    let config_file = path()?;
    let mut file = fs::File::create(config_file)?;
    file.write_all(toml::to_string(&config)?.as_bytes())?;
    Ok(())
}

/// Ensure that a string is a valid JSON pointer
///
/// Replaces dots (`.`) with slashes (`/`) and ensures a
/// leading slash.
#[tracing::instrument]
pub fn json_pointer(pointer: &str) -> String {
    let pointer = pointer.replace(".", "/");
    if pointer.starts_with('/') {
        pointer
    } else {
        format!("/{}", pointer)
    }
}

/// Display a config property
#[tracing::instrument]
pub fn display(config: &Config, pointer: Option<String>) -> Result<String> {
    match pointer {
        None => Ok(toml::to_string(config)?),
        Some(pointer) => {
            let config = serde_json::to_value(config)?;
            if let Some(part) = config.pointer(json_pointer(&pointer).as_str()) {
                let json = serde_json::to_string(part)?;
                let part: toml::Value = serde_json::from_str(&json)?;
                let toml = toml::to_string(&part)?;
                Ok(toml)
            } else {
                bail!("No configuration value at pointer: {}", pointer)
            }
        }
    }
}

/// Set a config property
#[tracing::instrument]
pub fn set(config: &Config, pointer: &str, value: &str) -> Result<Config> {
    let mut config = serde_json::to_value(config)?;
    if let Some(property) = config.pointer_mut(json_pointer(&pointer).as_str()) {
        let value = match serde_json::from_str(&value) {
            Ok(value) => value,
            Err(_) => serde_json::Value::String(value.into()),
        };
        *property = value;
    } else {
        bail!("No configuration value at pointer: {}", pointer)
    };

    let config: Config = serde_json::from_value(config)?;
    if let Err(errors) = config.validate() {
        bail!(
            "Invalid configuration value/s:\n\n{}",
            serde_json::to_string_pretty(&errors)?
        )
    }
    Ok(config)
}

/// Reset a config property
#[tracing::instrument]
pub fn reset(config: &Config, property: &str) -> Result<Config> {
    Ok(match property {
        "all" => Default::default(),
        "logging" => Config {
            logging: Default::default(),
            ..config.clone()
        },
        "plugins" => Config {
            plugins: Default::default(),
            ..config.clone()
        },
        "serve" => Config {
            serve: Default::default(),
            ..config.clone()
        },
        "upgrade" => Config {
            upgrade: Default::default(),
            ..config.clone()
        },
        _ => bail!("No top level configuration property named: {}", property),
    })
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration options",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Args {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Reset(Reset),

        #[structopt(
            about = "Get the directories used for config, cache etc",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Dirs,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Get configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Get {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: Option<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Set {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: String,

        /// The value to set the property to
        pub value: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Reset configuration properties to their defaults",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Reset {
        /// The config property to reset. Use 'all' to reset the entire config.
        pub property: String,
    }

    pub fn run(args: Args, config: &Config) -> Result<Config> {
        let Args { action } = args;
        match action {
            Action::Get(action) => {
                let Get { pointer } = action;
                println!("{}", super::display(config, pointer)?);
                Ok(config.clone())
            }
            Action::Set(action) => {
                let Set { pointer, value } = action;
                let config = super::set(config, &pointer, &value)?;
                write(&config)?;
                Ok(config)
            }
            Action::Reset(action) => {
                let Reset { property } = action;
                let config = super::reset(config, &property)?;
                write(&config)?;
                Ok(config)
            }
            Action::Dirs => {
                let config_dir = util::dirs::config(false)?.display().to_string();
                let plugins_dir = util::dirs::plugins(false)?.display().to_string();
                println!("config: {}\nplugins: {}", config_dir, plugins_dir);
                Ok(config.clone())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;

    use super::*;

    #[test]
    fn test_path() -> Result<()> {
        let path = path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_json_pointer() {
        assert_eq!(json_pointer("a"), "/a");
        assert_eq!(json_pointer("a/b"), "/a/b");
        assert_eq!(json_pointer("/a.b"), "/a/b");
        assert_eq!(json_pointer("a.b.c"), "/a/b/c");
    }

    #[test]
    fn test_display() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        let all = display(&config, None)?;
        assert!(all.contains("[serve]\n"));
        assert!(all.contains("[upgrade]\n"));

        let serve = display(&config, Some("serve".to_string()))?;
        assert!(!serve.contains("[serve]\n"));
        assert!(serve.contains("url = "));

        let upgrade = display(&config, Some("upgrade".to_string()))?;
        assert!(!upgrade.contains("[upgrade]\n"));
        assert!(upgrade.contains("auto = "));

        assert_eq!(
            display(&config, Some("foo.bar".to_string()))
                .unwrap_err()
                .to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[test]
    fn test_set() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        let result = set(&config, "upgrade.auto", "off")?;
        assert_eq!(result.upgrade.auto, "off");

        let result = set(&config, "upgrade.verbose", "true")?;
        assert_eq!(result.upgrade.verbose, true);

        assert_eq!(
            set(&config, "foo.bar", "baz").unwrap_err().to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[test]
    fn test_reset() -> Result<()> {
        let config = serde_json::from_value(json!({
            "upgrade": {
                "auto": "off",
                "verbose": true,
                "confirm": true,
            }
        }))?;

        let default = Config {
            ..Default::default()
        };

        let result = reset(&config, "upgrade")?;
        assert_eq!(result.upgrade.auto, default.upgrade.auto);
        assert_eq!(result.upgrade.verbose, default.upgrade.verbose);

        let result = reset(&config, "all")?;
        assert_eq!(result, default);

        assert_eq!(
            reset(&config, "foo").unwrap_err().to_string(),
            "No top level configuration property named: foo"
        );

        Ok(())
    }

    #[test]
    fn test_cli() -> Result<()> {
        use super::cli::*;

        let config = Config {
            ..Default::default()
        };

        run(
            Args {
                action: Action::Get(Get { pointer: None }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Set(Set {
                    pointer: "upgrade.confirm".to_string(),
                    value: "true".to_string(),
                }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Reset(Reset {
                    property: "upgrade".to_string(),
                }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Dirs,
            },
            &config,
        )?;

        Ok(())
    }
}
<commit_msg>fix(Config): Add logs directory to dirs command<commit_after>use crate::util;
use anyhow::{bail, Result};
use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use validator::Validate;

#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, Validate)]
pub struct Config {
    #[serde(default)]
    #[validate]
    pub logging: crate::logging::config::Config,

    #[serde(default)]
    #[validate]
    pub serve: crate::serve::config::Config,

    #[serde(default)]
    #[validate]
    pub plugins: crate::plugins::config::Config,

    #[serde(default)]
    #[validate]
    pub upgrade: crate::upgrade::config::Config,
}

const CONFIG_FILE: &str = "config.toml";

/// Get the path of the configuration file
#[tracing::instrument]
fn path() -> Result<PathBuf> {
    #[cfg(not(test))]
    return Ok(util::dirs::config(true)?.join(CONFIG_FILE));

    // When running tests, avoid messing with users existing config
    #[cfg(test)]
    {
        let path = std::env::temp_dir()
            .join("stencila")
            .join("test")
            .join(CONFIG_FILE);
        fs::create_dir_all(path.parent().unwrap())?;
        Ok(path)
    }
}

/// Read a config from the configuration file
#[tracing::instrument]
pub fn read() -> Result<Config> {
    let config_file = path()?;

    let content = if config_file.exists() {
        match fs::read_to_string(config_file.clone()) {
            Ok(content) => content,
            // If there was a problem reading the config file warn the user
            // but return an empty string.
            Err(error) => {
                tracing::warn!("Error while reading config file: {}", error.to_string());
                String::new()
            }
        }
    } else {
        // If there is no config file just return an empty string
        String::new()
    };

    let config = match toml::from_str(content.as_str()) {
        Ok(config) => config,
        // If there was a problem reading the config file. e.g syntax error, a change
        // in the enum variants for an option, then warn the user and return the
        // defaults instead. This avoids a "corrupt" config file from preventing the
        // user from doing anything.
        Err(error) => {
            tracing::warn!(
                "Error while parsing config file; use `stencila config reset all` or edit {} to fix; defaults will be used: {}",
                config_file.display(),
                error.to_string()
            );
            Config {
                ..Default::default()
            }
        }
    };

    if let Err(errors) = config.validate() {
        tracing::error!(
            "Invalid config file; use `stencila config set`, `stencila config reset` or edit {} to fix.\n\n{}",
            config_file.display(),
            serde_json::to_string_pretty(&errors)?
        )
    }

    Ok(config)
}

/// Write a config to the configuration file
#[tracing::instrument]
fn write(config: &Config) -> Result<()> {
    let config_file = path()?;
    let mut file = fs::File::create(config_file)?;
    file.write_all(toml::to_string(&config)?.as_bytes())?;
    Ok(())
}

/// Ensure that a string is a valid JSON pointer
///
/// Replaces dots (`.`) with slashes (`/`) and ensures a
/// leading slash.
#[tracing::instrument]
pub fn json_pointer(pointer: &str) -> String {
    let pointer = pointer.replace(".", "/");
    if pointer.starts_with('/') {
        pointer
    } else {
        format!("/{}", pointer)
    }
}

/// Display a config property
#[tracing::instrument]
pub fn display(config: &Config, pointer: Option<String>) -> Result<String> {
    match pointer {
        None => Ok(toml::to_string(config)?),
        Some(pointer) => {
            let config = serde_json::to_value(config)?;
            if let Some(part) = config.pointer(json_pointer(&pointer).as_str()) {
                let json = serde_json::to_string(part)?;
                let part: toml::Value = serde_json::from_str(&json)?;
                let toml = toml::to_string(&part)?;
                Ok(toml)
            } else {
                bail!("No configuration value at pointer: {}", pointer)
            }
        }
    }
}

/// Set a config property
#[tracing::instrument]
pub fn set(config: &Config, pointer: &str, value: &str) -> Result<Config> {
    let mut config = serde_json::to_value(config)?;
    if let Some(property) = config.pointer_mut(json_pointer(&pointer).as_str()) {
        let value = match serde_json::from_str(&value) {
            Ok(value) => value,
            Err(_) => serde_json::Value::String(value.into()),
        };
        *property = value;
    } else {
        bail!("No configuration value at pointer: {}", pointer)
    };

    let config: Config = serde_json::from_value(config)?;
    if let Err(errors) = config.validate() {
        bail!(
            "Invalid configuration value/s:\n\n{}",
            serde_json::to_string_pretty(&errors)?
        )
    }
    Ok(config)
}

/// Reset a config property
#[tracing::instrument]
pub fn reset(config: &Config, property: &str) -> Result<Config> {
    Ok(match property {
        "all" => Default::default(),
        "logging" => Config {
            logging: Default::default(),
            ..config.clone()
        },
        "plugins" => Config {
            plugins: Default::default(),
            ..config.clone()
        },
        "serve" => Config {
            serve: Default::default(),
            ..config.clone()
        },
        "upgrade" => Config {
            upgrade: Default::default(),
            ..config.clone()
        },
        _ => bail!("No top level configuration property named: {}", property),
    })
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration options",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Args {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Reset(Reset),

        #[structopt(
            about = "Get the directories used for config, cache etc",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Dirs,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Get configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Get {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: Option<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Set {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: String,

        /// The value to set the property to
        pub value: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Reset configuration properties to their defaults",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Reset {
        /// The config property to reset. Use 'all' to reset the entire config.
        pub property: String,
    }

    pub fn run(args: Args, config: &Config) -> Result<Config> {
        let Args { action } = args;
        match action {
            Action::Get(action) => {
                let Get { pointer } = action;
                println!("{}", super::display(config, pointer)?);
                Ok(config.clone())
            }
            Action::Set(action) => {
                let Set { pointer, value } = action;
                let config = super::set(config, &pointer, &value)?;
                write(&config)?;
                Ok(config)
            }
            Action::Reset(action) => {
                let Reset { property } = action;
                let config = super::reset(config, &property)?;
                write(&config)?;
                Ok(config)
            }
            Action::Dirs => {
                let config_dir = util::dirs::config(false)?.display().to_string();
                let logs_dir = util::dirs::logs(false)?.display().to_string();
                let plugins_dir = util::dirs::plugins(false)?.display().to_string();
                println!(
                    "config: {}\nlogs: {}\nplugins: {}",
                    config_dir, logs_dir, plugins_dir
                );
                Ok(config.clone())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;

    use super::*;

    #[test]
    fn test_path() -> Result<()> {
        let path = path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_json_pointer() {
        assert_eq!(json_pointer("a"), "/a");
        assert_eq!(json_pointer("a/b"), "/a/b");
        assert_eq!(json_pointer("/a.b"), "/a/b");
        assert_eq!(json_pointer("a.b.c"), "/a/b/c");
    }

    #[test]
    fn test_display() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        let all = display(&config, None)?;
        assert!(all.contains("[serve]\n"));
        assert!(all.contains("[upgrade]\n"));

        let serve = display(&config, Some("serve".to_string()))?;
        assert!(!serve.contains("[serve]\n"));
        assert!(serve.contains("url = "));

        let upgrade = display(&config, Some("upgrade".to_string()))?;
        assert!(!upgrade.contains("[upgrade]\n"));
        assert!(upgrade.contains("auto = "));

        assert_eq!(
            display(&config, Some("foo.bar".to_string()))
                .unwrap_err()
                .to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[test]
    fn test_set() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        let result = set(&config, "upgrade.auto", "off")?;
        assert_eq!(result.upgrade.auto, "off");

        let result = set(&config, "upgrade.verbose", "true")?;
        assert_eq!(result.upgrade.verbose, true);

        assert_eq!(
            set(&config, "foo.bar", "baz").unwrap_err().to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[test]
    fn test_reset() -> Result<()> {
        let config = serde_json::from_value(json!({
            "upgrade": {
                "auto": "off",
                "verbose": true,
                "confirm": true,
            }
        }))?;

        let default = Config {
            ..Default::default()
        };

        let result = reset(&config, "upgrade")?;
        assert_eq!(result.upgrade.auto, default.upgrade.auto);
        assert_eq!(result.upgrade.verbose, default.upgrade.verbose);

        let result = reset(&config, "all")?;
        assert_eq!(result, default);

        assert_eq!(
            reset(&config, "foo").unwrap_err().to_string(),
            "No top level configuration property named: foo"
        );

        Ok(())
    }

    #[test]
    fn test_cli() -> Result<()> {
        use super::cli::*;

        let config = Config {
            ..Default::default()
        };

        run(
            Args {
                action: Action::Get(Get { pointer: None }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Set(Set {
                    pointer: "upgrade.confirm".to_string(),
                    value: "true".to_string(),
                }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Reset(Reset {
                    property: "upgrade".to_string(),
                }),
            },
            &config,
        )?;

        run(
            Args {
                action: Action::Dirs,
            },
            &config,
        )?;

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


<commit_before>#[doc(hidden)]
#[macro_export]
macro_rules! uuid_based_wrapper_type {
    (
        $(#[$outer:meta])*
        $struct_name: ident
    ) => {
        $(#[$outer])*
        #[derive(
            Debug,
            Copy,
            Clone,
            serde::Deserialize,
            serde::Serialize,
            Hash,
            Ord,
            PartialOrd,
            Eq,
            PartialEq,
        )]
        pub struct $struct_name(uuid::Uuid);

        impl std::fmt::Display for $struct_name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                std::fmt::Display::fmt(&self.0, f)
            }
        }

        impl From<$struct_name> for uuid::Uuid {
            fn from(id: $struct_name) -> Self {
                id.0
            }
        }

        impl $struct_name {
            pub(super) fn new() -> Self {
                $struct_name(uuid::Uuid::new_v4())
            }
        }

        impl From<$struct_name> for crate::worker::SubscriptionTarget {
            fn from(id: $struct_name) -> Self {
                Self::Uuid(id.0)
            }
        }
    };
}
<commit_msg>rust: properly use  in a macro definition<commit_after>#[doc(hidden)]
#[macro_export]
macro_rules! uuid_based_wrapper_type {
    (
        $(#[$outer:meta])*
        $struct_name: ident
    ) => {
        $(#[$outer])*
        #[derive(
            Debug,
            Copy,
            Clone,
            serde::Deserialize,
            serde::Serialize,
            Hash,
            Ord,
            PartialOrd,
            Eq,
            PartialEq,
        )]
        pub struct $struct_name(uuid::Uuid);

        impl std::fmt::Display for $struct_name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                std::fmt::Display::fmt(&self.0, f)
            }
        }

        impl From<$struct_name> for uuid::Uuid {
            fn from(id: $struct_name) -> Self {
                id.0
            }
        }

        impl $struct_name {
            pub(super) fn new() -> Self {
                $struct_name(uuid::Uuid::new_v4())
            }
        }

        impl From<$struct_name> for $crate::worker::SubscriptionTarget {
            fn from(id: $struct_name) -> Self {
                Self::Uuid(id.0)
            }
        }
    };
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::ptr;
use std::rc::Rc;
extern crate libc;

use cnode::*;
use drawing_ctx;
use drawing_ctx::*;
use handle::RsvgHandle;
use marker;
use node::*;
use path_builder::*;
use path_parser;
use property_bag;
use property_bag::*;
use state::RsvgState;

struct NodePath {
    builder: RefCell<RsvgPathBuilder>
}

impl NodePath {
    fn new () -> NodePath {
        NodePath {
            builder: RefCell::new (RsvgPathBuilder::new ())
        }
    }
}

impl NodeTrait for NodePath {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        if let Some (value) = property_bag::lookup (pbag, "d") {
            let mut builder = self.builder.borrow_mut ();

            if let Err (_) = path_parser::parse_path_into_builder (&value, &mut *builder) {
                // FIXME: we don't propagate errors upstream, but creating a partial
                // path is OK per the spec
            }
        }
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        let builder = &*self.builder.borrow ();

        drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);
        drawing_ctx::render_path_builder (draw_ctx, builder);
        marker::render_markers_for_path_builder (builder, draw_ctx);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        ptr::null ()
    }
}

#[no_mangle]
pub extern fn rsvg_node_path_new (element_name: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
    box_node (Rc::new (Node::new (NodeType::Path,
                                  parent_ptr_to_weak (raw_parent),
                                  drawing_ctx::state_new (),
                                  Box::new (NodePath::new ()))))
}
<commit_msg>shapes.rs: Factor out function to render a path builder<commit_after>use std::cell::RefCell;
use std::ptr;
use std::rc::Rc;
extern crate libc;

use cnode::*;
use drawing_ctx;
use drawing_ctx::*;
use handle::RsvgHandle;
use marker;
use node::*;
use path_builder::*;
use path_parser;
use property_bag;
use property_bag::*;
use state::RsvgState;

fn render_path_builder (builder:  &RsvgPathBuilder,
                        draw_ctx: *const RsvgDrawingCtx,
                        state:    *mut RsvgState,
                        dominate: i32,
                        render_markers: bool) {
    drawing_ctx::state_reinherit_top (draw_ctx, state, dominate);
    drawing_ctx::render_path_builder (draw_ctx, builder);

    if render_markers {
        marker::render_markers_for_path_builder (builder, draw_ctx);
    }
}

/***** NodePath *****/

struct NodePath {
    builder: RefCell<RsvgPathBuilder>
}

impl NodePath {
    fn new () -> NodePath {
        NodePath {
            builder: RefCell::new (RsvgPathBuilder::new ())
        }
    }
}

impl NodeTrait for NodePath {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        if let Some (value) = property_bag::lookup (pbag, "d") {
            let mut builder = self.builder.borrow_mut ();

            if let Err (_) = path_parser::parse_path_into_builder (&value, &mut *builder) {
                // FIXME: we don't propagate errors upstream, but creating a partial
                // path is OK per the spec
            }
        }
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        render_path_builder (&*self.builder.borrow (), draw_ctx, node.get_state (), dominate, true);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        ptr::null ()
    }
}

/***** C Prototypes *****/

#[no_mangle]
pub extern fn rsvg_node_path_new (element_name: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
    box_node (Rc::new (Node::new (NodeType::Path,
                                  parent_ptr_to_weak (raw_parent),
                                  drawing_ctx::state_new (),
                                  Box::new (NodePath::new ()))))
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)]

//! [Github](https://github.com/rusterlium/rustler)
//! [Example](https://github.com/hansihe/Rustler_Example)
//!
//! Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no
//! ways to crash the BEAM (Erlang VM). The library provides facilities for generating the
//! boilerplate for interacting with the BEAM, handles encoding and decoding of Erlang terms, and
//! catches rust panics before they unwind into C.
//!
//! The library provides functionality for both Erlang and Elixir, however Elixir is favored as of
//! now.
//!
//! This crate provides the entire runtime library for rustler. Code generators are located in the
//! rustler_codegen library.
//!
//! # Getting Started
//! There is a [`:rustler`](https://hex.pm/packages/rustler) package on hex.pm that provides
//! functionality which makes working with Rustler easier, including project generators, an
//! automatic NIF compiler for Mix, and utilities for loading the compiled NIF.
//!
//! For more information about this, see [the documentation for
//! rustler_mix](https://hexdocs.pm/rustler/basics.html).

#[macro_use(enif_snprintf)]
extern crate rustler_sys;

#[doc(hidden)]
pub mod wrapper;

#[doc(hidden)]
pub mod codegen_runtime;

pub extern crate lazy_static;

#[macro_use]
pub mod types;

mod term;

pub use crate::term::Term;
pub use crate::types::{
    Atom, Binary, Decoder, Encoder, ListIterator, LocalPid, MapIterator, OwnedBinary,
};
pub mod resource;
pub use crate::resource::ResourceArc;

#[doc(hidden)]
pub mod dynamic;
pub use crate::dynamic::TermType;

pub mod schedule;
pub use crate::schedule::SchedulerFlags;
pub mod env;
pub use crate::env::{Env, OwnedEnv};
pub mod thread;
pub use crate::thread::{spawn, JobSpawner, ThreadSpawner};

pub mod error;
pub mod export;
pub use crate::error::Error;

pub mod r#return;
pub use crate::r#return::Return;

#[doc(hidden)]
mod nif;
pub use nif::Nif;

pub type NifResult<T> = Result<T, Error>;

#[cfg(feature = "derive")]
pub use rustler_codegen::{
    init, nif, NifMap, NifRecord, NifStruct, NifTuple, NifUnitEnum, NifUntaggedEnum,
};
<commit_msg>Point to HexDocs base URL for Rustler in lib.rs<commit_after>#![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)]

//! [Github](https://github.com/rusterlium/rustler)
//! [Example](https://github.com/hansihe/Rustler_Example)
//!
//! Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no
//! ways to crash the BEAM (Erlang VM). The library provides facilities for generating the
//! boilerplate for interacting with the BEAM, handles encoding and decoding of Erlang terms, and
//! catches rust panics before they unwind into C.
//!
//! The library provides functionality for both Erlang and Elixir, however Elixir is favored as of
//! now.
//!
//! This crate provides the entire runtime library for rustler. Code generators are located in the
//! rustler_codegen library.
//!
//! # Getting Started
//! There is a [`:rustler`](https://hex.pm/packages/rustler) package on hex.pm that provides
//! functionality which makes working with Rustler easier, including project generators, an
//! automatic NIF compiler for Mix, and utilities for loading the compiled NIF.
//!
//! For more information about this, see [the documentation for
//! rustler](https://hexdocs.pm/rustler).

#[macro_use(enif_snprintf)]
extern crate rustler_sys;

#[doc(hidden)]
pub mod wrapper;

#[doc(hidden)]
pub mod codegen_runtime;

pub extern crate lazy_static;

#[macro_use]
pub mod types;

mod term;

pub use crate::term::Term;
pub use crate::types::{
    Atom, Binary, Decoder, Encoder, ListIterator, LocalPid, MapIterator, OwnedBinary,
};
pub mod resource;
pub use crate::resource::ResourceArc;

#[doc(hidden)]
pub mod dynamic;
pub use crate::dynamic::TermType;

pub mod schedule;
pub use crate::schedule::SchedulerFlags;
pub mod env;
pub use crate::env::{Env, OwnedEnv};
pub mod thread;
pub use crate::thread::{spawn, JobSpawner, ThreadSpawner};

pub mod error;
pub mod export;
pub use crate::error::Error;

pub mod r#return;
pub use crate::r#return::Return;

#[doc(hidden)]
mod nif;
pub use nif::Nif;

pub type NifResult<T> = Result<T, Error>;

#[cfg(feature = "derive")]
pub use rustler_codegen::{
    init, nif, NifMap, NifRecord, NifStruct, NifTuple, NifUnitEnum, NifUntaggedEnum,
};
<|endoftext|>


<commit_before>use std::str::Chars;
use std::iter::Iterator;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TokenType {
    Character,
    NewLine,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ArmorToken {
    token_type: TokenType,
    token: char,
}

impl ArmorToken {
    pub fn new(token_type: TokenType, token: char) -> ArmorToken {
        ArmorToken {
            token_type: token_type,
            token: token,
        }
    }

    pub fn valid_token(&self) -> bool {
        match self.token {
            '\n' | '\r' => self.token_type == TokenType::NewLine,
            _           => self.token_type == TokenType::Character,
        }
    }
}

pub struct ArmorLexer<'a> {
    stream: String,
    chars:  Chars<'a>,
}

impl<'a> ArmorLexer<'a> {
    pub fn new(stream: &String) -> ArmorLexer {
        let new_stream = stream.clone();

        ArmorLexer {
            stream: new_stream,
            chars:  stream.chars(),
        }
    }

    pub fn next_token(&mut self) -> Option<ArmorToken> {
        let next_char = self.chars.next();

        match next_char {
            None                    => None,
            Some('\n') | Some('\r') => Some(ArmorToken::new(TokenType::NewLine, '\n')),
            Some(character)         => Some(ArmorToken::new(TokenType::Character, character)),
        }
    }
}

impl<'a> Iterator for ArmorLexer<'a> {
    type Item = ArmorToken;

    fn next(&mut self) -> Option<ArmorToken> {
        self.next_token()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.chars.size_hint()
    }
}
<commit_msg>Add whitespace token type to lexer.<commit_after>use std::str::Chars;
use std::iter::Iterator;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TokenType {
    Character,
    NewLine,
    WhiteSpace,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ArmorToken {
    token_type: TokenType,
    token: char,
}

impl ArmorToken {
    pub fn new(token_type: TokenType, token: char) -> ArmorToken {
        ArmorToken {
            token_type: token_type,
            token: token,
        }
    }

    pub fn valid_token(&self) -> bool {
        match self.token {
            ' '  | '\t' => self.token_type == TokenType::WhiteSpace,
            '\n' | '\r' => self.token_type == TokenType::NewLine,
            _           => self.token_type == TokenType::Character,
        }
    }
}

pub struct ArmorLexer<'a> {
    stream: String,
    chars:  Chars<'a>,
}

impl<'a> ArmorLexer<'a> {
    pub fn new(stream: &String) -> ArmorLexer {
        let new_stream = stream.clone();

        ArmorLexer {
            stream: new_stream,
            chars:  stream.chars(),
        }
    }

    pub fn next_token(&mut self) -> Option<ArmorToken> {
        let next_char = self.chars.next();

        match next_char {
            None                    => None,
            Some(' ')  | Some('\t') => Some(ArmorToken::new(TokenType::WhiteSpace, ' ')),
            Some('\n') | Some('\r') => Some(ArmorToken::new(TokenType::NewLine, '\n')),
            Some(character)         => Some(ArmorToken::new(TokenType::Character, character)),
        }
    }
}

impl<'a> Iterator for ArmorLexer<'a> {
    type Item = ArmorToken;

    fn next(&mut self) -> Option<ArmorToken> {
        self.next_token()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.chars.size_hint()
    }
}
<|endoftext|>


<commit_before>use cgmath::Vector2;
use std::f32::consts::*;

pub type Position = Vector2<f32>;
pub type Translation = Vector2<f32>;

#[derive(Clone, Default)]
pub struct Size {
	pub width: f32,
	pub height: f32,
}

#[derive(Copy, Clone)]
pub struct Transform {
	pub position: Position,
	pub angle: f32,
	pub scale: f32,
}

impl Default for Transform {
	fn default() -> Transform {
		Transform {
			position: Position::new(0., 0.),
			angle: 0.,
			scale: 1.,
		}
	}
}
impl Transform {
	pub fn with_position(position: Position) -> Self {
		Transform { position: position, ..Transform::default() }
	}
}
pub type Rgba = [f32; 4];
pub type Id = usize;
pub type LimbIndex = u8;
pub type BoneIndex = u8;
pub type AttachmentIndex = u8;
pub type PhysicsHandle = Id;

#[derive(Clone)]
pub enum Shape {
	Ball {
		radius: f32,
	},
	Box {
		width: f32,
		height: f32,
	},
	Star {
		// http://www.geocities.jp/nyjp07/index_asteroid_E.html
		radius: f32,
		n: u8,
		a: f32,
		b: f32,
		c: f32,
		ratio: f32,
	},
	Triangle {
		radius: f32,
		alpha1: f32,
		alpha2: f32,
	},
}

impl Shape {
	pub fn radius(&self) -> f32 {
		match self {
			&Shape::Ball { radius } => radius,
			&Shape::Box { height, .. } => height / 2.,
			&Shape::Star { radius, .. } => radius,
			&Shape::Triangle { radius, .. } => radius,
		}
	}
}

#[derive(Clone, Copy)]
pub enum Winding {
	CW = 1,
	CCW = -1,
}

impl Winding {
	pub fn xunit(&self) -> f32 {
		*self as i16 as f32
	}
}

impl Shape {
	pub fn new_ball(r: f32) -> Self {
		Shape::Ball { radius: r }
	}

	pub fn new_box(width: f32, height: f32) -> Self {
		Shape::Box {
			width: width,
			height: height,
		}
	}

	pub fn new_star(radius: f32, ratio: f32, n: u8) -> Self {
		assert!(radius > 0.);
		assert!(n > 1);
		Shape::Star {
			radius: radius,
			n: n,
			a: 0.83255,
			b: 0.14,
			c: 1.,
			ratio: ratio,
		}
	}

	pub fn new_triangle(radius: f32, alpha1: f32, alpha2: f32) -> Self {
		Shape::Triangle {
			radius: radius,
			alpha1: alpha1,
			alpha2: alpha2,
		}
	}

	pub fn vertices(&self, winding: Winding) -> Vec<Position> {
		let xunit = winding.xunit();
		match self {
			// first point is always unit y
			&Shape::Ball { .. } => {
				let n = 12usize;
				(0..n)
					.map(|i| {
						let p = (i as f32) / (n as f32) * 2. * PI;
						Position::new(xunit * f32::sin(p), f32::cos(p))
					})
					.collect()
			}
			&Shape::Box { width, height } => {
				let w2 = xunit * width / height;
				vec![Position::new(0., 1.),
				     Position::new(w2, 1.),
				     Position::new(-w2, -1.),
				     Position::new(w2, -1.),
				     Position::new(-w2, 1.)]
			}
			&Shape::Star { n, a, b, c, ratio, .. } => {
				let mut damp = 1.0;
				let xmax = f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - 1.) / (b * b));
				let r0 = ratio * xmax;
				// we want r in 0 to be 1
				let rmax = r0 + (1. / c) * f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - 1.));

				(0..(2 * n))
					.map(|i| {
						let p = i as f32 * (PI / n as f32);
						let s = f32::sin(p * (n as f32 / 2.));
						let r = (r0 +
						         (1. / c) *
						         f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - f32::exp(-b * b * xmax * xmax * s * s)))) /
						        rmax;
						damp *= 0.9;
						Position::new(xunit * damp * r * f32::sin(p), damp * r * f32::cos(p))
					})
					.collect()
			}
			&Shape::Triangle { alpha1, alpha2, .. } => {
				vec![Position::new(0., 1.),
				     Position::new(xunit * f32::sin(alpha1 * PI), f32::cos(alpha1 * PI)),
				     Position::new(xunit * f32::sin(alpha2 * PI), f32::cos(alpha2 * PI))]
			}
		}
	}
}

pub struct Mesh {
	pub shape: Shape,
	pub winding: Winding,
	pub vertices: Vec<Position>,
}

impl Mesh {
	pub fn from_shape(shape: Shape, winding: Winding) -> Self {
		let vertices = shape.vertices(winding);
		Mesh {
			shape: shape,
			winding: winding,
			vertices: vertices,
		}
	}
}

pub trait Transformable {
	fn transform(&self) -> Transform;
	fn transform_to(&mut self, t: Transform);
}

pub trait GameObject: Transformable {
	fn id(&self) -> Id;
}

#[derive(Copy, Clone)]
pub struct Material {
	pub density: f32,
	pub restitution: f32,
	pub friction: f32,
}

impl Default for Material {
	fn default() -> Self {
		Material {
			density: 1.0,
			restitution: 0.2,
			friction: 0.3,
		}
	}
}

pub trait Updateable {
	fn update(&mut self, dt: f32);
}

pub trait Solid {
	fn material(&self) -> Material;
}

pub trait Geometry {
	fn mesh(&self) -> &Mesh;
}

pub trait Drawable: Geometry {
	fn color(&self) -> Rgba;
}
<commit_msg>Friction tweak<commit_after>use cgmath::Vector2;
use std::f32::consts::*;

pub type Position = Vector2<f32>;
pub type Translation = Vector2<f32>;

#[derive(Clone, Default)]
pub struct Size {
	pub width: f32,
	pub height: f32,
}

#[derive(Copy, Clone)]
pub struct Transform {
	pub position: Position,
	pub angle: f32,
	pub scale: f32,
}

impl Default for Transform {
	fn default() -> Transform {
		Transform {
			position: Position::new(0., 0.),
			angle: 0.,
			scale: 1.,
		}
	}
}
impl Transform {
	pub fn with_position(position: Position) -> Self {
		Transform { position: position, ..Transform::default() }
	}
}
pub type Rgba = [f32; 4];
pub type Id = usize;
pub type LimbIndex = u8;
pub type BoneIndex = u8;
pub type AttachmentIndex = u8;
pub type PhysicsHandle = Id;

#[derive(Clone)]
pub enum Shape {
	Ball {
		radius: f32,
	},
	Box {
		width: f32,
		height: f32,
	},
	Star {
		// http://www.geocities.jp/nyjp07/index_asteroid_E.html
		radius: f32,
		n: u8,
		a: f32,
		b: f32,
		c: f32,
		ratio: f32,
	},
	Triangle {
		radius: f32,
		alpha1: f32,
		alpha2: f32,
	},
}

impl Shape {
	pub fn radius(&self) -> f32 {
		match self {
			&Shape::Ball { radius } => radius,
			&Shape::Box { height, .. } => height / 2.,
			&Shape::Star { radius, .. } => radius,
			&Shape::Triangle { radius, .. } => radius,
		}
	}
}

#[derive(Clone, Copy)]
pub enum Winding {
	CW = 1,
	CCW = -1,
}

impl Winding {
	pub fn xunit(&self) -> f32 {
		*self as i16 as f32
	}
}

impl Shape {
	pub fn new_ball(r: f32) -> Self {
		Shape::Ball { radius: r }
	}

	pub fn new_box(width: f32, height: f32) -> Self {
		Shape::Box {
			width: width,
			height: height,
		}
	}

	pub fn new_star(radius: f32, ratio: f32, n: u8) -> Self {
		assert!(radius > 0.);
		assert!(n > 1);
		Shape::Star {
			radius: radius,
			n: n,
			a: 0.83255,
			b: 0.14,
			c: 1.,
			ratio: ratio,
		}
	}

	pub fn new_triangle(radius: f32, alpha1: f32, alpha2: f32) -> Self {
		Shape::Triangle {
			radius: radius,
			alpha1: alpha1,
			alpha2: alpha2,
		}
	}

	pub fn vertices(&self, winding: Winding) -> Vec<Position> {
		let xunit = winding.xunit();
		match self {
			// first point is always unit y
			&Shape::Ball { .. } => {
				let n = 12usize;
				(0..n)
					.map(|i| {
						let p = (i as f32) / (n as f32) * 2. * PI;
						Position::new(xunit * f32::sin(p), f32::cos(p))
					})
					.collect()
			}
			&Shape::Box { width, height } => {
				let w2 = xunit * width / height;
				vec![Position::new(0., 1.),
				     Position::new(w2, 1.),
				     Position::new(-w2, -1.),
				     Position::new(w2, -1.),
				     Position::new(-w2, 1.)]
			}
			&Shape::Star { n, a, b, c, ratio, .. } => {
				let mut damp = 1.0;
				let xmax = f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - 1.) / (b * b));
				let r0 = ratio * xmax;
				// we want r in 0 to be 1
				let rmax = r0 + (1. / c) * f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - 1.));

				(0..(2 * n))
					.map(|i| {
						let p = i as f32 * (PI / n as f32);
						let s = f32::sin(p * (n as f32 / 2.));
						let r = (r0 +
						         (1. / c) *
						         f32::sqrt(-f32::ln(2. * f32::exp(-a * a) - f32::exp(-b * b * xmax * xmax * s * s)))) /
						        rmax;
						damp *= 0.9;
						Position::new(xunit * damp * r * f32::sin(p), damp * r * f32::cos(p))
					})
					.collect()
			}
			&Shape::Triangle { alpha1, alpha2, .. } => {
				vec![Position::new(0., 1.),
				     Position::new(xunit * f32::sin(alpha1 * PI), f32::cos(alpha1 * PI)),
				     Position::new(xunit * f32::sin(alpha2 * PI), f32::cos(alpha2 * PI))]
			}
		}
	}
}

pub struct Mesh {
	pub shape: Shape,
	pub winding: Winding,
	pub vertices: Vec<Position>,
}

impl Mesh {
	pub fn from_shape(shape: Shape, winding: Winding) -> Self {
		let vertices = shape.vertices(winding);
		Mesh {
			shape: shape,
			winding: winding,
			vertices: vertices,
		}
	}
}

pub trait Transformable {
	fn transform(&self) -> Transform;
	fn transform_to(&mut self, t: Transform);
}

pub trait GameObject: Transformable {
	fn id(&self) -> Id;
}

#[derive(Copy, Clone)]
pub struct Material {
	pub density: f32,
	pub restitution: f32,
	pub friction: f32,
}

impl Default for Material {
	fn default() -> Self {
		Material {
			density: 1.0,
			restitution: 0.6,
			friction: 0.7,
		}
	}
}

pub trait Updateable {
	fn update(&mut self, dt: f32);
}

pub trait Solid {
	fn material(&self) -> Material;
}

pub trait Geometry {
	fn mesh(&self) -> &Mesh;
}

pub trait Drawable: Geometry {
	fn color(&self) -> Rgba;
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// xfail-test
struct HTMLImageData {
    image: Option<~str>
}

struct ElementData {
    kind: ~ElementKind
}

enum ElementKind {
    HTMLImageElement(HTMLImageData)
}

enum NodeKind {
    Element(ElementData)
}

enum NodeData = {
    kind: ~NodeKind
};

fn main() {
    let mut id = HTMLImageData { image: None };
    let ed = ElementData { kind: ~HTMLImageElement(id) };
    let n = NodeData({kind : ~Element(ed)});
    match n.kind {
        ~Element(ed) => match ed.kind {
            ~HTMLImageElement(d) if d.image.is_some() => { true }
        },
        _ => fail!(~"WAT") //~ ERROR wat
    };
}
<commit_msg>auto merge of #5152 : catamorphism/rust/issue-3601, r=catamorphism<commit_after>// Copyright 2012-2013 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.

struct HTMLImageData {
    image: Option<~str>
}

struct ElementData {
    kind: ~ElementKind
}

enum ElementKind {
    HTMLImageElement(HTMLImageData)
}

enum NodeKind {
    Element(ElementData)
}

struct NodeData {
    kind: ~NodeKind
}

fn main() {
    let mut id = HTMLImageData { image: None };
    let ed = ElementData { kind: ~HTMLImageElement(id) };
    let n = NodeData {kind : ~Element(ed)};
    // n.b. span could be better
    match n.kind {
        ~Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
            ~HTMLImageElement(ref d) if d.image.is_some() => { true }
        },
        _ => fail!(~"WAT") //~ ERROR unreachable pattern
    };
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

struct Bike {
    name: ~str,
}

trait BikeMethods {
    fn woops(&const self) -> ~str;
}

impl BikeMethods for Bike {
    fn woops(&const self) -> ~str { ~"foo" }
    //~^ ERROR method `woops` is declared as static in its impl, but not in its trait
}

pub fn main() {
}
<commit_msg>test: Fix test. rs=test<commit_after>// Copyright 2012 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.

struct Bike {
    name: ~str,
}

trait BikeMethods {
    fn woops(&const self) -> ~str;
}

impl BikeMethods for Bike {
    fn woops() -> ~str { ~"foo" }
    //~^ ERROR method `woops` is declared as static in its impl, but not in its trait
}

pub fn main() {
}
<|endoftext|>