<commit_before>//! A LinkedList that lets you insert elements from the front or the end of the list.
//! TODO: Add the ability to insert in-between a Node.
//! Lots of thanks to reem and Sharp for help with this from the #rust channel

use std::mem;

/// A Node is the basic unit in a LinkedList which stores the payload of type T.
#[derive(Debug,PartialEq)]
struct Node<T> {
    /// The payload of type T that is wrapped aorund a Node.
    pub payload: T,
    /// An Option of a boxed Node<T> that would point to the next Node<T>.
    next: Option<Box<Node<T>>>,
    /// An Option of a boxed Node<T> that would point to the previous Node<T>.
    prev: Option<Box<Node<T>>>,
}

impl<T> Node<T> {

    pub fn new(payload: T) -> Node<T> {
        //! Creates a instance of a `Node` with `next` and `prev` point to a Option::Node.
        Node::<T> {
            payload: payload,
            next: None,
            prev: None,
        }
    }

    pub fn payload(&self) -> Option<&T> {
        //! Access to a payload of Node.
        Some(&self.payload)
    }

    pub fn insert_after(&mut self, mut new: Box<Node<T>>) -> Option<Box<Node<T>>> {
        //! Takes a new boxed Node<T> and swaps it with any existing Node after the current one.
        //! We replace any Option::None or Option::Some with a new Option<Box<Node<T>>>
        mem::swap(&mut new.next, &mut self.next);
        mem::replace(&mut self.next, Some(new))
    }

    pub fn insert_before(&mut self, mut new: Box<Node<T>>) -> Option<Box<Node<T>>> {
        //! Takes a new boxed Node<T> and swaps it with any existing Node after the current one.
        //! We replace any Option::None or Option::Some with a new Option<Box<Node<T>>>
        mem::swap(&mut new.prev, &mut self.prev);
        mem::replace(&mut self.prev, Some(new))
    }

    pub fn remove_after(&mut self) -> Option<Box<Node<T>>> {
        //! Removes the Node after the current node.
        match self.next.take() {
            Some(mut next)  => {
                mem::swap(&mut self.next, &mut next.next);
                Some(next)
            },
            None => None,
        }
    }

    pub fn remove_before(&mut self) -> Option<Box<Node<T>>> {
        //! Removes the Node before the current node.
        match self.prev.take() {
            Some(mut prev)  => {
                mem::swap(&mut self.prev, &mut prev.prev);
                Some(prev)
            },
            None => None,
        }
    }

    pub fn next(&mut self) -> Option<&mut T> {
        //! Goes to the next Node and returns an Option to it.
        let Node {
            ref mut payload,
            ref mut prev,
            ref mut next,
        } = *self;

        match *next {
            Some(ref mut next) => {
                mem::swap(&mut next.payload, payload);

                let mut next = &mut **next;     // Cannot completely understand this bit yet.
                mem::swap(&mut next.next, &mut next.prev);

                mem::swap(&mut next.prev, prev);
            },
            None => return None,
        }
        mem::swap(prev, next);
        Some(payload)
    }

    pub fn prev(&mut self) -> Option<&mut T> {
        let Node {
            ref mut payload,
            ref mut prev,
            ref mut next,
        } = *self;

        match *prev {
            Some(ref mut prev) => {
                mem::swap(&mut prev.payload, payload);

                let mut prev = &mut **prev;     // Still don't understand this bit.
                mem::swap(&mut prev.prev, &mut prev.next);

                mem::swap(&mut prev.next, next);
            },
            None => return None,
        }
        mem::swap(prev, next);
        Some(payload)
    }
}

/// A LinkedList is the struct that you would need to use to create a list of elements.
/// It contains a pointer to the first and last node in the list represented as `head and `tail`
/// respectively.
pub struct LinkedList<T> {
    /// First element in the list.
    head: Option<Box<Node<T>>>,
    /// Last element in the list.
    tail: Option<Box<Node<T>>>,
    /// Number of nodes in the list.
    size: usize,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        //! Create a new LinkedList to contain a payloads with type T.
        LinkedList::<T> {
            head: None,
            tail: None,
            size: 0,
        }
    }

    pub fn push_back(&mut self, mut new: T) {
        let new_node = Box::new(Node::new(new));
        //if self.size == 0 {
            // Then `head` and `tail` need to point to the same node.
            // But can I do that in rust? Have one point as mutable and the other as immutable?!
        //} else {
            match self.tail {
                Some(ref mut tail_node) => {
                    tail_node.insert_before(new_node);
                },
                None => {
                    mem::swap(&mut self.tail, &mut Some(new_node));
                },
            }
        //}
        self.size += 1;
    }
}

#[test]
fn node_new() {
    let expected = Node {
        payload: "test",
        next: None,
        prev: None,
    };

    let node: Node<&str> = Node::new("test");

    assert_eq!(expected.payload,  node.payload);
    assert_eq!(expected.next,     node.next);
    assert_eq!(expected.prev,     node.prev);
}

#[test]
fn node_payload() {
    let node: Node<&str> = Node::new("test");
    assert_eq!(&"test", node.payload().unwrap());
}

#[test]
fn node_insert_after() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    assert_eq!("two", node.next.unwrap().payload);
}

#[test]
fn node_insert_before() {
    let mut node: Node<&str> = Node::new("two");
    node.insert_before(Box::new(Node::new("one")));
    assert_eq!("one", node.prev.unwrap().payload);
}

#[test]
fn node_remove_next() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    node.remove_after();
}

#[test]
fn node_remove_prev() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_before(Box::new(Node::new("two")));
    node.remove_before();
}

#[test]
fn node_next() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    assert_eq!("two", *node.next().unwrap());
}

#[test]
fn node_prev() {
    let mut node: Node<&str> = Node::new("two");
    node.insert_before(Box::new(Node::new("one")));
    assert_eq!("one", *node.prev().unwrap());
}

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

    //#[test]
    fn test_push_back() {
        let mut list: LinkedList<String> = LinkedList::new();
        list.push_back("one".to_string());
        assert_eq!("one".to_string(), list.tail.unwrap().payload);
    }

    #[test]
    fn test_push_back_two() {
        let mut list: LinkedList<String> = LinkedList::new();
        list.push_back("one".to_string());
        list.push_back("two".to_string());
        //assert_eq!("one".to_string(), list.tail.unwrap().payload);
        assert_eq!("one".to_string(), list.tail.unwrap().prev.unwrap().payload);
    }

}
<commit_msg>Comments, TODOs and logic<commit_after>//! A LinkedList that lets you insert elements from the front or the end of the list.
//! TODO: Add the ability to insert in-between a Node.
//! Lots of thanks to reem and Sharp for help with this from the #rust channel

use std::mem;

/// A Node is the basic unit in a LinkedList which stores the payload of type T.
#[derive(Debug,PartialEq)]
struct Node<T> {
    /// The payload of type T that is wrapped aorund a Node.
    pub payload: T,
    /// An Option of a boxed Node<T> that would point to the next Node<T>.
    next: Option<Box<Node<T>>>,
    /// An Option of a boxed Node<T> that would point to the previous Node<T>.
    prev: Option<Box<Node<T>>>,
}

impl<T> Node<T> {

    pub fn new(payload: T) -> Node<T> {
        //! Creates a instance of a `Node` with `next` and `prev` point to a Option::Node.
        Node::<T> {
            payload: payload,
            next: None,
            prev: None,
        }
    }

    pub fn payload(&self) -> Option<&T> {
        //! Access to a payload of Node.
        Some(&self.payload)
    }

    pub fn insert_after(&mut self, mut new: Box<Node<T>>) -> Option<Box<Node<T>>> {
        //! Takes a new boxed Node<T> and swaps it with any existing Node after the current one.
        //! We replace any Option::None or Option::Some with a new Option<Box<Node<T>>>
        mem::swap(&mut new.next, &mut self.next);
        mem::replace(&mut self.next, Some(new))
    }

    pub fn insert_before(&mut self, mut new: Box<Node<T>>) -> Option<Box<Node<T>>> {
        //! Takes a new boxed Node<T> and swaps it with any existing Node after the current one.
        //! We replace any Option::None or Option::Some with a new Option<Box<Node<T>>>
        mem::swap(&mut new.prev, &mut self.prev);
        mem::replace(&mut self.prev, Some(new))
    }

    pub fn remove_after(&mut self) -> Option<Box<Node<T>>> {
        //! Removes the Node after the current node.
        match self.next.take() {
            Some(mut next)  => {
                mem::swap(&mut self.next, &mut next.next);
                Some(next)
            },
            None => None,
        }
    }

    pub fn remove_before(&mut self) -> Option<Box<Node<T>>> {
        //! Removes the Node before the current node.
        match self.prev.take() {
            Some(mut prev)  => {
                mem::swap(&mut self.prev, &mut prev.prev);
                Some(prev)
            },
            None => None,
        }
    }

    pub fn next(&mut self) -> Option<&mut T> {
        //! Goes to the next Node and returns an Option to it.
        let Node {
            ref mut payload,
            ref mut prev,
            ref mut next,
        } = *self;

        match *next {
            Some(ref mut next) => {
                mem::swap(&mut next.payload, payload);

                let mut next = &mut **next;     // Cannot completely understand this bit yet.
                mem::swap(&mut next.next, &mut next.prev);

                mem::swap(&mut next.prev, prev);
            },
            None => return None,
        }
        mem::swap(prev, next);
        Some(payload)
    }

    pub fn prev(&mut self) -> Option<&mut T> {
        let Node {
            ref mut payload,
            ref mut prev,
            ref mut next,
        } = *self;

        match *prev {
            Some(ref mut prev) => {
                mem::swap(&mut prev.payload, payload);

                let mut prev = &mut **prev;     // Still don't understand this bit.
                mem::swap(&mut prev.prev, &mut prev.next);

                mem::swap(&mut prev.next, next);
            },
            None => return None,
        }
        mem::swap(prev, next);
        Some(payload)
    }
}

/// A LinkedList is the struct that you would need to use to create a list of elements.
/// It contains a pointer to the first and last node in the list represented as `head and `tail`
/// respectively.
pub struct LinkedList<T> {
    /// First element in the list.
    head: Option<Box<Node<T>>>,
    /// Last element in the list.
    tail: Option<Box<Node<T>>>,
    /// Number of nodes in the list.
    size: usize,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        //! Create a new LinkedList to contain a payloads with type T.
        LinkedList::<T> {
            head: None,
            tail: None,
            size: 0,
        }
    }

    pub fn push_back(&mut self, mut new: T) {
        let new_node = Box::new(Node::new(new));
        if self.size == 0 {
            // Then `head` and `tail` need to point to the same node.
            // But can I do that in rust? Have one point as mutable and the other as immutable?!

            // FIXME Create a reference to `head` and `tail` from new_node

            // FIXME Remove placeholder linked Node for tail
            match self.tail {
                Some(ref mut tail_node) => {
                    tail_node.insert_before(new_node);
                },
                None => {
                    mem::swap(&mut self.tail, &mut Some(new_node));
                },
            }
        } else {
            match self.tail {
                Some(ref mut tail_node) => {
                    tail_node.insert_before(new_node);
                    // FIXME Replace tail_node with new_node reference
                },
                None => {
                    mem::swap(&mut self.tail, &mut Some(new_node));
                },
            }
        }
        self.size += 1;
    }
}

#[test]
fn node_new() {
    let expected = Node {
        payload: "test",
        next: None,
        prev: None,
    };

    let node: Node<&str> = Node::new("test");

    assert_eq!(expected.payload,  node.payload);
    assert_eq!(expected.next,     node.next);
    assert_eq!(expected.prev,     node.prev);
}

#[test]
fn node_payload() {
    let node: Node<&str> = Node::new("test");
    assert_eq!(&"test", node.payload().unwrap());
}

#[test]
fn node_insert_after() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    assert_eq!("two", node.next.unwrap().payload);
}

#[test]
fn node_insert_before() {
    let mut node: Node<&str> = Node::new("two");
    node.insert_before(Box::new(Node::new("one")));
    assert_eq!("one", node.prev.unwrap().payload);
}

#[test]
fn node_remove_next() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    node.remove_after();
}

#[test]
fn node_remove_prev() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_before(Box::new(Node::new("two")));
    node.remove_before();
}

#[test]
fn node_next() {
    let mut node: Node<&str> = Node::new("one");
    node.insert_after(Box::new(Node::new("two")));
    assert_eq!("two", *node.next().unwrap());
}

#[test]
fn node_prev() {
    let mut node: Node<&str> = Node::new("two");
    node.insert_before(Box::new(Node::new("one")));
    assert_eq!("one", *node.prev().unwrap());
}

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

    //#[test]
    fn test_push_back() {
        let mut list: LinkedList<String> = LinkedList::new();
        list.push_back("one".to_string());
        assert_eq!("one".to_string(), list.tail.unwrap().payload);
    }

    #[test]
    fn test_push_back_two() {
        let mut list: LinkedList<String> = LinkedList::new();
        list.push_back("one".to_string());
        list.push_back("two".to_string());
        //assert_eq!("one".to_string(), list.tail.unwrap().payload);
        assert_eq!("one".to_string(), list.tail.unwrap().prev.unwrap().payload);
    }

}
<|endoftext|>


<commit_before>use std::hash::{Hasher, BuildHasher};
use super::{Projection, SparseProjection};
use geometry::RegularSpace;
use geometry::dimensions::Continuous;
use ndarray::Array1;

#[derive(Serialize, Deserialize)]
pub struct TileCoding<H: BuildHasher> {
    hasher_builder: H,
    n_tilings: usize,
    memory_size: usize,
}

impl<H: BuildHasher> TileCoding<H> {
    pub fn new(hasher_builder: H, n_tilings: usize, memory_size: usize) -> Self {
        TileCoding {
            hasher_builder: hasher_builder,
            n_tilings: n_tilings,
            memory_size: memory_size,
        }
    }
}

impl<H: BuildHasher> Projection<RegularSpace<Continuous>> for TileCoding<H> {
    fn project_onto(&self, input: &Vec<f64>, phi: &mut Array1<f64>) {
        for t in self.project_sparse(input).iter() {
            phi[*t] = 1.0;
        }
    }

    fn dim(&self) -> usize {
        unimplemented!()
    }

    fn size(&self) -> usize {
        self.memory_size as usize
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.size() == other.size() && self.n_tilings == other.n_tilings &&
        self.memory_size == other.memory_size
    }
}

impl<H: BuildHasher> SparseProjection<RegularSpace<Continuous>> for TileCoding<H> {
    fn project_onto_sparse(&self, input: &Vec<f64>, indices: &mut Array1<usize>) {
        let mut hasher = self.hasher_builder.build_hasher();

        let n_floats = input.len();
        let floats: Vec<usize> =
            input.iter().map(|f| (*f * self.n_tilings as f64).floor() as usize).collect();

        for t in 0..self.n_tilings {
            hasher.write_usize(t);
            for i in 0..n_floats {
                hasher.write_usize((floats[i] + t + i*t*2) / self.n_tilings)
            }

            indices[t] = hasher.finish() as usize % self.memory_size;
        }
    }

    fn sparsity(&self) -> usize {
        self.n_tilings
    }
}
<commit_msg>fix(TileCoding): use l2 norm in TileCoding rep<commit_after>use std::hash::{Hasher, BuildHasher};
use super::{Projection, SparseProjection};
use geometry::RegularSpace;
use geometry::norms::l2;
use geometry::dimensions::Continuous;
use ndarray::Array1;

#[derive(Clone, Serialize, Deserialize)]
pub struct TileCoding<H: BuildHasher> {
    hasher_builder: H,
    n_tilings: usize,
    memory_size: usize,
    activation: f64,
}

impl<H: BuildHasher> TileCoding<H> {
    pub fn new(hasher_builder: H, n_tilings: usize, memory_size: usize) -> Self {
        TileCoding {
            hasher_builder: hasher_builder,
            n_tilings: n_tilings,
            memory_size: memory_size,
            activation: 1.0/l2(&vec![1.0; n_tilings]),
        }
    }
}

impl<H: BuildHasher> Projection<RegularSpace<Continuous>> for TileCoding<H> {
    fn project_onto(&self, input: &Vec<f64>, phi: &mut Array1<f64>) {
        for t in self.project_sparse(input).iter() {
            phi[*t] = self.activation;
        }
    }

    fn dim(&self) -> usize {
        unimplemented!()
    }

    fn size(&self) -> usize {
        self.memory_size as usize
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.size() == other.size() && self.n_tilings == other.n_tilings &&
        self.memory_size == other.memory_size
    }
}

impl<H: BuildHasher> SparseProjection<RegularSpace<Continuous>> for TileCoding<H> {
    fn project_onto_sparse(&self, input: &Vec<f64>, indices: &mut Array1<usize>) {
        let mut hasher = self.hasher_builder.build_hasher();

        let n_floats = input.len();
        let floats: Vec<usize> =
            input.iter().map(|f| (*f * self.n_tilings as f64).floor() as usize).collect();

        for t in 0..self.n_tilings {
            hasher.write_usize(t);
            for i in 0..n_floats {
                hasher.write_usize((floats[i] + t + i*t*2) / self.n_tilings)
            }

            indices[t] = hasher.finish() as usize % self.memory_size;
        }
    }

    fn sparsity(&self) -> usize {
        self.n_tilings
    }
}
<|endoftext|>


<commit_before>pub struct LineIterator<'a> {
    data: &'a str,
    start: usize,
    end: usize
}

impl<'a> LineIterator<'a> {
    pub fn new<'b>(data: &'b str) -> LineIterator<'b> {
        LineIterator{ data: data, start: 0, end: 0 }
    }

    pub fn done(&self) -> bool {
        self.end == self.data.len()
    }
}

impl<'a> Iterator for LineIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done() {
            return None
        }

        // Move the range beyond its previous position.
        self.start = self.end;

        // Find the next line range.
        for (offset, c) in self.data[self.start..].char_indices() {
            // Extend the current line range to include this char.
            self.end += c.len_utf8();

            if c == '\n' {
                println!("char: {}", c);
                println!("offset: {}", offset);
                break;
            }
        }

        Some(&self.data[self.start..self.end])
    }
}

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

    #[test]
    fn next_includes_trailing_newlines() {
        let mut lines = LineIterator::new("line\nanother line\n");
        assert_eq!(Some("line\n"), lines.next());
        assert_eq!(Some("another line\n"), lines.next());
    }

    #[test]
    fn next_stops_at_end_of_data() {
        let mut lines = LineIterator::new("line\nanother line\n");
        lines.next();
        lines.next();
        assert_eq!(None, lines.next());
    }
}
<commit_msg>Remove print debug statements from line iterator.<commit_after>pub struct LineIterator<'a> {
    data: &'a str,
    start: usize,
    end: usize
}

impl<'a> LineIterator<'a> {
    pub fn new<'b>(data: &'b str) -> LineIterator<'b> {
        LineIterator{ data: data, start: 0, end: 0 }
    }

    pub fn done(&self) -> bool {
        self.end == self.data.len()
    }
}

impl<'a> Iterator for LineIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done() {
            return None
        }

        // Move the range beyond its previous position.
        self.start = self.end;

        // Find the next line range.
        for (offset, c) in self.data[self.start..].char_indices() {
            // Extend the current line range to include this char.
            self.end += c.len_utf8();

            if c == '\n' {
                break;
            }
        }

        Some(&self.data[self.start..self.end])
    }
}

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

    #[test]
    fn next_includes_trailing_newlines() {
        let mut lines = LineIterator::new("line\nanother line\n");
        assert_eq!(Some("line\n"), lines.next());
        assert_eq!(Some("another line\n"), lines.next());
    }

    #[test]
    fn next_stops_at_end_of_data() {
        let mut lines = LineIterator::new("line\nanother line\n");
        lines.next();
        lines.next();
        assert_eq!(None, lines.next());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;

use semver::Version;
use url::Url;

use core::PackageId;
use util::{ToSemver, ToUrl};
use util::errors::{CargoResult, CargoResultExt};

/// Some or all of the data required to indentify a package:
///
///  1. the package name (a `String`, required)
///  2. the package version (a `Version`, optional)
///  3. the package source (a `Url`, optional)
///
/// If any of the optional fields are omitted, then the package id may be ambiguous, there may be
/// more than one package/version/url combo that will match. However, often just the name is
/// sufficient to uniquely define a package id.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PackageIdSpec {
    name: String,
    version: Option<Version>,
    url: Option<Url>,
}

impl PackageIdSpec {
    /// Parses a spec string and returns a `PackageIdSpec` if the string was valid.
    ///
    /// # Examples
    /// Some examples of valid strings
    ///
    /// ```
    /// use cargo::core::PackageIdSpec;
    ///
    /// let specs = vec![
    ///     "http://crates.io/foo#1.2.3",
    ///     "http://crates.io/foo#bar:1.2.3",
    ///     "crates.io/foo",
    ///     "crates.io/foo#1.2.3",
    ///     "crates.io/foo#bar",
    ///     "crates.io/foo#bar:1.2.3",
    ///     "foo",
    ///     "foo:1.2.3",
    /// ];
    /// for spec in specs {
    ///     assert!(PackageIdSpec::parse(spec).is_ok());
    /// }
    pub fn parse(spec: &str) -> CargoResult<PackageIdSpec> {
        if spec.contains('/') {
            if let Ok(url) = spec.to_url() {
                return PackageIdSpec::from_url(url);
            }
            if !spec.contains("://") {
                if let Ok(url) = Url::parse(&format!("cargo://{}", spec)) {
                    return PackageIdSpec::from_url(url);
                }
            }
        }
        let mut parts = spec.splitn(2, ':');
        let name = parts.next().unwrap();
        let version = match parts.next() {
            Some(version) => Some(Version::parse(version)?),
            None => None,
        };
        for ch in name.chars() {
            if !ch.is_alphanumeric() && ch != '_' && ch != '-' {
                bail!("invalid character in pkgid `{}`: `{}`", spec, ch)
            }
        }
        Ok(PackageIdSpec {
            name: name.to_string(),
            version,
            url: None,
        })
    }

    /// Roughly equivalent to `PackageIdSpec::parse(spec)?.query(i)`
    pub fn query_str<'a, I>(spec: &str, i: I) -> CargoResult<&'a PackageId>
    where
        I: IntoIterator<Item = &'a PackageId>,
    {
        let spec = PackageIdSpec::parse(spec)
            .chain_err(|| format_err!("invalid package id specification: `{}`", spec))?;
        spec.query(i)
    }

    /// Convert a `PackageId` to a `PackageIdSpec`, which will have both the `Version` and `Url`
    /// fields filled in.
    pub fn from_package_id(package_id: &PackageId) -> PackageIdSpec {
        PackageIdSpec {
            name: package_id.name().to_string(),
            version: Some(package_id.version().clone()),
            url: Some(package_id.source_id().url().clone()),
        }
    }

    /// Tries to convert a valid `Url` to a `PackageIdSpec`.
    fn from_url(mut url: Url) -> CargoResult<PackageIdSpec> {
        if url.query().is_some() {
            bail!("cannot have a query string in a pkgid: {}", url)
        }
        let frag = url.fragment().map(|s| s.to_owned());
        url.set_fragment(None);
        let (name, version) = {
            let mut path = url.path_segments()
                .ok_or_else(|| format_err!("pkgid urls must have a path: {}", url))?;
            let path_name = path.next_back().ok_or_else(|| {
                format_err!(
                    "pkgid urls must have at least one path \
                     component: {}",
                    url
                )
            })?;
            match frag {
                Some(fragment) => {
                    let mut parts = fragment.splitn(2, ':');
                    let name_or_version = parts.next().unwrap();
                    match parts.next() {
                        Some(part) => {
                            let version = part.to_semver()?;
                            (name_or_version.to_string(), Some(version))
                        }
                        None => {
                            if name_or_version.chars().next().unwrap().is_alphabetic() {
                                (name_or_version.to_string(), None)
                            } else {
                                let version = name_or_version.to_semver()?;
                                (path_name.to_string(), Some(version))
                            }
                        }
                    }
                }
                None => (path_name.to_string(), None),
            }
        };
        Ok(PackageIdSpec {
            name,
            version,
            url: Some(url),
        })
    }

    /// Getter for `name` field.
    pub fn name(&self) -> &str {
        &self.name
    }
    /// Getter for `version` field.
    pub fn version(&self) -> Option<&Version> {
        self.version.as_ref()
    }
    /// Getter for `url` field.
    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    /// Setter for `url` field.
    pub fn set_url(&mut self, url: Url) {
        self.url = Some(url);
    }

    /// Checkes whether the given `PackageId` matches the `PackageIdSpec`.
    pub fn matches(&self, package_id: &PackageId) -> bool {
        if self.name() != &*package_id.name() {
            return false;
        }

        if let Some(ref v) = self.version {
            if v != package_id.version() {
                return false;
            }
        }

        match self.url {
            Some(ref u) => u == package_id.source_id().url(),
            None => true,
        }
    }

    /// Checks a list of `PackageId`s to find 1 that matches this `PackageIdSpec`. If 0, 2, or
    /// more are found, then this returns an error.
    pub fn query<'a, I>(&self, i: I) -> CargoResult<&'a PackageId>
    where
        I: IntoIterator<Item = &'a PackageId>,
    {
        let mut ids = i.into_iter().filter(|p| self.matches(*p));
        let ret = match ids.next() {
            Some(id) => id,
            None => bail!(
                "package id specification `{}` \
                 matched no packages",
                self
            ),
        };
        return match ids.next() {
            Some(other) => {
                let mut msg = format!(
                    "There are multiple `{}` packages in \
                     your project, and the specification \
                     `{}` is ambiguous.\n\
                     Please re-run this command \
                     with `-p <spec>` where `<spec>` is one \
                     of the following:",
                    self.name(),
                    self
                );
                let mut vec = vec![ret, other];
                vec.extend(ids);
                minimize(&mut msg, &vec, self);
                Err(format_err!("{}", msg))
            }
            None => Ok(ret),
        };

        fn minimize(msg: &mut String, ids: &[&PackageId], spec: &PackageIdSpec) {
            let mut version_cnt = HashMap::new();
            for id in ids {
                *version_cnt.entry(id.version()).or_insert(0) += 1;
            }
            for id in ids {
                if version_cnt[id.version()] == 1 {
                    msg.push_str(&format!("\n  {}:{}", spec.name(), id.version()));
                } else {
                    msg.push_str(&format!("\n  {}", PackageIdSpec::from_package_id(*id)));
                }
            }
        }
    }
}

impl fmt::Display for PackageIdSpec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut printed_name = false;
        match self.url {
            Some(ref url) => {
                if url.scheme() == "cargo" {
                    write!(f, "{}{}", url.host().unwrap(), url.path())?;
                } else {
                    write!(f, "{}", url)?;
                }
                if url.path_segments().unwrap().next_back().unwrap() != self.name {
                    printed_name = true;
                    write!(f, "#{}", self.name)?;
                }
            }
            None => {
                printed_name = true;
                write!(f, "{}", self.name)?
            }
        }
        if let Some(ref v) = self.version {
            write!(f, "{}{}", if printed_name { ":" } else { "#" }, v)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use core::{PackageId, SourceId};
    use super::PackageIdSpec;
    use url::Url;
    use semver::Version;

    #[test]
    fn good_parsing() {
        fn ok(spec: &str, expected: PackageIdSpec) {
            let parsed = PackageIdSpec::parse(spec).unwrap();
            assert_eq!(parsed, expected);
            assert_eq!(parsed.to_string(), spec);
        }

        ok(
            "http://crates.io/foo#1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("http://crates.io/foo").unwrap()),
            },
        );
        ok(
            "http://crates.io/foo#bar:1.2.3",
            PackageIdSpec {
                name: "bar".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("http://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo",
            PackageIdSpec {
                name: "foo".to_string(),
                version: None,
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#bar",
            PackageIdSpec {
                name: "bar".to_string(),
                version: None,
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#bar:1.2.3",
            PackageIdSpec {
                name: "bar".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "foo",
            PackageIdSpec {
                name: "foo".to_string(),
                version: None,
                url: None,
            },
        );
        ok(
            "foo:1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: None,
            },
        );
    }

    #[test]
    fn bad_parsing() {
        assert!(PackageIdSpec::parse("baz:").is_err());
        assert!(PackageIdSpec::parse("baz:*").is_err());
        assert!(PackageIdSpec::parse("baz:1.0").is_err());
        assert!(PackageIdSpec::parse("http://baz:1.0").is_err());
        assert!(PackageIdSpec::parse("http://#baz:1.0").is_err());
    }

    #[test]
    fn matching() {
        let url = Url::parse("http://example.com").unwrap();
        let sid = SourceId::for_registry(&url).unwrap();
        let foo = PackageId::new("foo", "1.2.3", &sid).unwrap();
        let bar = PackageId::new("bar", "1.2.3", &sid).unwrap();

        assert!(PackageIdSpec::parse("foo").unwrap().matches(&foo));
        assert!(!PackageIdSpec::parse("foo").unwrap().matches(&bar));
        assert!(PackageIdSpec::parse("foo:1.2.3").unwrap().matches(&foo));
        assert!(!PackageIdSpec::parse("foo:1.2.2").unwrap().matches(&foo));
    }
}
<commit_msg>remove getter/setter docs<commit_after>use std::collections::HashMap;
use std::fmt;

use semver::Version;
use url::Url;

use core::PackageId;
use util::{ToSemver, ToUrl};
use util::errors::{CargoResult, CargoResultExt};

/// Some or all of the data required to indentify a package:
///
///  1. the package name (a `String`, required)
///  2. the package version (a `Version`, optional)
///  3. the package source (a `Url`, optional)
///
/// If any of the optional fields are omitted, then the package id may be ambiguous, there may be
/// more than one package/version/url combo that will match. However, often just the name is
/// sufficient to uniquely define a package id.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PackageIdSpec {
    name: String,
    version: Option<Version>,
    url: Option<Url>,
}

impl PackageIdSpec {
    /// Parses a spec string and returns a `PackageIdSpec` if the string was valid.
    ///
    /// # Examples
    /// Some examples of valid strings
    ///
    /// ```
    /// use cargo::core::PackageIdSpec;
    ///
    /// let specs = vec![
    ///     "http://crates.io/foo#1.2.3",
    ///     "http://crates.io/foo#bar:1.2.3",
    ///     "crates.io/foo",
    ///     "crates.io/foo#1.2.3",
    ///     "crates.io/foo#bar",
    ///     "crates.io/foo#bar:1.2.3",
    ///     "foo",
    ///     "foo:1.2.3",
    /// ];
    /// for spec in specs {
    ///     assert!(PackageIdSpec::parse(spec).is_ok());
    /// }
    pub fn parse(spec: &str) -> CargoResult<PackageIdSpec> {
        if spec.contains('/') {
            if let Ok(url) = spec.to_url() {
                return PackageIdSpec::from_url(url);
            }
            if !spec.contains("://") {
                if let Ok(url) = Url::parse(&format!("cargo://{}", spec)) {
                    return PackageIdSpec::from_url(url);
                }
            }
        }
        let mut parts = spec.splitn(2, ':');
        let name = parts.next().unwrap();
        let version = match parts.next() {
            Some(version) => Some(Version::parse(version)?),
            None => None,
        };
        for ch in name.chars() {
            if !ch.is_alphanumeric() && ch != '_' && ch != '-' {
                bail!("invalid character in pkgid `{}`: `{}`", spec, ch)
            }
        }
        Ok(PackageIdSpec {
            name: name.to_string(),
            version,
            url: None,
        })
    }

    /// Roughly equivalent to `PackageIdSpec::parse(spec)?.query(i)`
    pub fn query_str<'a, I>(spec: &str, i: I) -> CargoResult<&'a PackageId>
    where
        I: IntoIterator<Item = &'a PackageId>,
    {
        let spec = PackageIdSpec::parse(spec)
            .chain_err(|| format_err!("invalid package id specification: `{}`", spec))?;
        spec.query(i)
    }

    /// Convert a `PackageId` to a `PackageIdSpec`, which will have both the `Version` and `Url`
    /// fields filled in.
    pub fn from_package_id(package_id: &PackageId) -> PackageIdSpec {
        PackageIdSpec {
            name: package_id.name().to_string(),
            version: Some(package_id.version().clone()),
            url: Some(package_id.source_id().url().clone()),
        }
    }

    /// Tries to convert a valid `Url` to a `PackageIdSpec`.
    fn from_url(mut url: Url) -> CargoResult<PackageIdSpec> {
        if url.query().is_some() {
            bail!("cannot have a query string in a pkgid: {}", url)
        }
        let frag = url.fragment().map(|s| s.to_owned());
        url.set_fragment(None);
        let (name, version) = {
            let mut path = url.path_segments()
                .ok_or_else(|| format_err!("pkgid urls must have a path: {}", url))?;
            let path_name = path.next_back().ok_or_else(|| {
                format_err!(
                    "pkgid urls must have at least one path \
                     component: {}",
                    url
                )
            })?;
            match frag {
                Some(fragment) => {
                    let mut parts = fragment.splitn(2, ':');
                    let name_or_version = parts.next().unwrap();
                    match parts.next() {
                        Some(part) => {
                            let version = part.to_semver()?;
                            (name_or_version.to_string(), Some(version))
                        }
                        None => {
                            if name_or_version.chars().next().unwrap().is_alphabetic() {
                                (name_or_version.to_string(), None)
                            } else {
                                let version = name_or_version.to_semver()?;
                                (path_name.to_string(), Some(version))
                            }
                        }
                    }
                }
                None => (path_name.to_string(), None),
            }
        };
        Ok(PackageIdSpec {
            name,
            version,
            url: Some(url),
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn version(&self) -> Option<&Version> {
        self.version.as_ref()
    }

    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    pub fn set_url(&mut self, url: Url) {
        self.url = Some(url);
    }

    /// Checkes whether the given `PackageId` matches the `PackageIdSpec`.
    pub fn matches(&self, package_id: &PackageId) -> bool {
        if self.name() != &*package_id.name() {
            return false;
        }

        if let Some(ref v) = self.version {
            if v != package_id.version() {
                return false;
            }
        }

        match self.url {
            Some(ref u) => u == package_id.source_id().url(),
            None => true,
        }
    }

    /// Checks a list of `PackageId`s to find 1 that matches this `PackageIdSpec`. If 0, 2, or
    /// more are found, then this returns an error.
    pub fn query<'a, I>(&self, i: I) -> CargoResult<&'a PackageId>
    where
        I: IntoIterator<Item = &'a PackageId>,
    {
        let mut ids = i.into_iter().filter(|p| self.matches(*p));
        let ret = match ids.next() {
            Some(id) => id,
            None => bail!(
                "package id specification `{}` \
                 matched no packages",
                self
            ),
        };
        return match ids.next() {
            Some(other) => {
                let mut msg = format!(
                    "There are multiple `{}` packages in \
                     your project, and the specification \
                     `{}` is ambiguous.\n\
                     Please re-run this command \
                     with `-p <spec>` where `<spec>` is one \
                     of the following:",
                    self.name(),
                    self
                );
                let mut vec = vec![ret, other];
                vec.extend(ids);
                minimize(&mut msg, &vec, self);
                Err(format_err!("{}", msg))
            }
            None => Ok(ret),
        };

        fn minimize(msg: &mut String, ids: &[&PackageId], spec: &PackageIdSpec) {
            let mut version_cnt = HashMap::new();
            for id in ids {
                *version_cnt.entry(id.version()).or_insert(0) += 1;
            }
            for id in ids {
                if version_cnt[id.version()] == 1 {
                    msg.push_str(&format!("\n  {}:{}", spec.name(), id.version()));
                } else {
                    msg.push_str(&format!("\n  {}", PackageIdSpec::from_package_id(*id)));
                }
            }
        }
    }
}

impl fmt::Display for PackageIdSpec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut printed_name = false;
        match self.url {
            Some(ref url) => {
                if url.scheme() == "cargo" {
                    write!(f, "{}{}", url.host().unwrap(), url.path())?;
                } else {
                    write!(f, "{}", url)?;
                }
                if url.path_segments().unwrap().next_back().unwrap() != self.name {
                    printed_name = true;
                    write!(f, "#{}", self.name)?;
                }
            }
            None => {
                printed_name = true;
                write!(f, "{}", self.name)?
            }
        }
        if let Some(ref v) = self.version {
            write!(f, "{}{}", if printed_name { ":" } else { "#" }, v)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use core::{PackageId, SourceId};
    use super::PackageIdSpec;
    use url::Url;
    use semver::Version;

    #[test]
    fn good_parsing() {
        fn ok(spec: &str, expected: PackageIdSpec) {
            let parsed = PackageIdSpec::parse(spec).unwrap();
            assert_eq!(parsed, expected);
            assert_eq!(parsed.to_string(), spec);
        }

        ok(
            "http://crates.io/foo#1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("http://crates.io/foo").unwrap()),
            },
        );
        ok(
            "http://crates.io/foo#bar:1.2.3",
            PackageIdSpec {
                name: "bar".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("http://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo",
            PackageIdSpec {
                name: "foo".to_string(),
                version: None,
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#bar",
            PackageIdSpec {
                name: "bar".to_string(),
                version: None,
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "crates.io/foo#bar:1.2.3",
            PackageIdSpec {
                name: "bar".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: Some(Url::parse("cargo://crates.io/foo").unwrap()),
            },
        );
        ok(
            "foo",
            PackageIdSpec {
                name: "foo".to_string(),
                version: None,
                url: None,
            },
        );
        ok(
            "foo:1.2.3",
            PackageIdSpec {
                name: "foo".to_string(),
                version: Some(Version::parse("1.2.3").unwrap()),
                url: None,
            },
        );
    }

    #[test]
    fn bad_parsing() {
        assert!(PackageIdSpec::parse("baz:").is_err());
        assert!(PackageIdSpec::parse("baz:*").is_err());
        assert!(PackageIdSpec::parse("baz:1.0").is_err());
        assert!(PackageIdSpec::parse("http://baz:1.0").is_err());
        assert!(PackageIdSpec::parse("http://#baz:1.0").is_err());
    }

    #[test]
    fn matching() {
        let url = Url::parse("http://example.com").unwrap();
        let sid = SourceId::for_registry(&url).unwrap();
        let foo = PackageId::new("foo", "1.2.3", &sid).unwrap();
        let bar = PackageId::new("bar", "1.2.3", &sid).unwrap();

        assert!(PackageIdSpec::parse("foo").unwrap().matches(&foo));
        assert!(!PackageIdSpec::parse("foo").unwrap().matches(&bar));
        assert!(PackageIdSpec::parse("foo:1.2.3").unwrap().matches(&foo));
        assert!(!PackageIdSpec::parse("foo:1.2.2").unwrap().matches(&foo));
    }
}
<|endoftext|>


<commit_before>#![feature(track_caller, core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => (core::panic::Location::caller());
}

fn main() {
    let location = Location::caller();
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), 23);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), 28);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), 45);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), 50);
    assert_eq!(intrinsic.column(), 21);
}
<commit_msg>test track_caller with fn ptrs<commit_after>#![feature(track_caller, core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => (core::panic::Location::caller());
}

fn test_fn_ptr() {
    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
        f(x);
    }

    #[track_caller]
    fn tracked_unit(_: ()) {
        let expected_line = line!() - 1;
        let location = std::panic::Location::caller();
        assert_eq!(location.file(), file!());
        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
    }

    pass_to_ptr_call(tracked_unit, ());
}

fn main() {
    let location = Location::caller();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    let expected_line = line!() - 1;
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), expected_line);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    let expected_line = line!() - 1;
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), expected_line);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    let expected_line = line!() - 1;
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), expected_line);
    assert_eq!(intrinsic.column(), 21);

    test_fn_ptr();
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{Factory, Result, Swarm, Version};
use rand::rngs::StdRng;
use std::{
    collections::HashMap,
    num::NonZeroUsize,
    path::{Path, PathBuf},
    sync::Arc,
};

mod cargo;
mod node;
mod swarm;
pub use node::LocalNode;
pub use swarm::{LocalSwarm, LocalSwarmBuilder, SwarmDirectory};

#[derive(Clone, Debug)]
pub struct LocalVersion {
    revision: String,
    bin: PathBuf,
    version: Version,
}

impl LocalVersion {
    fn bin(&self) -> &Path {
        &self.bin
    }

    fn version(&self) -> Version {
        self.version.clone()
    }
}

pub struct LocalFactory {
    versions: Arc<HashMap<Version, LocalVersion>>,
}

impl LocalFactory {
    pub fn new(versions: HashMap<Version, LocalVersion>) -> Self {
        Self {
            versions: Arc::new(versions),
        }
    }

    pub fn from_workspace() -> Result<Self> {
        let mut versions = HashMap::new();
        let new_version = cargo::get_diem_node_binary_from_worktree().map(|(revision, bin)| {
            let version = Version::new(usize::max_value(), revision.clone());
            LocalVersion {
                revision,
                bin,
                version,
            }
        })?;

        versions.insert(new_version.version.clone(), new_version);
        Ok(Self::new(versions))
    }

    pub fn from_revision(revision: &str) -> Result<Self> {
        let mut versions = HashMap::new();
        let new_version =
            cargo::get_diem_node_binary_at_revision(revision).map(|(revision, bin)| {
                let version = Version::new(usize::max_value(), revision.clone());
                LocalVersion {
                    revision,
                    bin,
                    version,
                }
            })?;

        versions.insert(new_version.version.clone(), new_version);
        Ok(Self::new(versions))
    }

    pub fn with_revision_and_workspace(revision: &str) -> Result<Self> {
        let workspace = cargo::get_diem_node_binary_from_worktree().map(|(revision, bin)| {
            let version = Version::new(usize::max_value(), revision.clone());
            LocalVersion {
                revision,
                bin,
                version,
            }
        })?;
        let revision =
            cargo::get_diem_node_binary_at_revision(revision).map(|(revision, bin)| {
                let version = Version::new(usize::min_value(), revision.clone());
                LocalVersion {
                    revision,
                    bin,
                    version,
                }
            })?;

        let mut versions = HashMap::new();
        versions.insert(workspace.version(), workspace);
        versions.insert(revision.version(), revision);
        Ok(Self::new(versions))
    }

    /// Create a LocalFactory with a diem-node version built at the tip of upstream/main and the
    /// current workspace, suitable for compatibility testing.
    pub fn with_upstream_and_workspace() -> Result<Self> {
        let upstream_main = cargo::git_get_upstream_remote().map(|r| format!("{}/main", r))?;
        Self::with_revision_and_workspace(&upstream_main)
    }

    /// Create a LocalFactory with a diem-node version built at merge-base of upstream/main and the
    /// current workspace, suitable for compatibility testing.
    pub fn with_upstream_merge_base_and_workspace() -> Result<Self> {
        let upstream_main = cargo::git_get_upstream_remote().map(|r| format!("{}/main", r))?;
        let merge_base = cargo::git_merge_base(upstream_main)?;
        Self::with_revision_and_workspace(&merge_base)
    }
}

impl Factory for LocalFactory {
    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        Box::new(self.versions.keys().cloned())
    }

    fn launch_swarm(
        &self,
        rng: &mut StdRng,
        node_num: NonZeroUsize,
        version: &Version,
    ) -> Result<Box<dyn Swarm>> {
        let mut swarm = LocalSwarm::builder(self.versions.clone())
            .number_of_validators(node_num)
            .initial_version(version.clone())
            .build(rng)?;
        swarm.launch()?;

        Ok(Box::new(swarm))
    }
}
<commit_msg>forge: persist logs if the swarm can't be started<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{Factory, Result, Swarm, Version};
use anyhow::Context;
use rand::rngs::StdRng;
use std::{
    collections::HashMap,
    num::NonZeroUsize,
    path::{Path, PathBuf},
    sync::Arc,
};

mod cargo;
mod node;
mod swarm;
pub use node::LocalNode;
pub use swarm::{LocalSwarm, LocalSwarmBuilder, SwarmDirectory};

#[derive(Clone, Debug)]
pub struct LocalVersion {
    revision: String,
    bin: PathBuf,
    version: Version,
}

impl LocalVersion {
    fn bin(&self) -> &Path {
        &self.bin
    }

    fn version(&self) -> Version {
        self.version.clone()
    }
}

pub struct LocalFactory {
    versions: Arc<HashMap<Version, LocalVersion>>,
}

impl LocalFactory {
    pub fn new(versions: HashMap<Version, LocalVersion>) -> Self {
        Self {
            versions: Arc::new(versions),
        }
    }

    pub fn from_workspace() -> Result<Self> {
        let mut versions = HashMap::new();
        let new_version = cargo::get_diem_node_binary_from_worktree().map(|(revision, bin)| {
            let version = Version::new(usize::max_value(), revision.clone());
            LocalVersion {
                revision,
                bin,
                version,
            }
        })?;

        versions.insert(new_version.version.clone(), new_version);
        Ok(Self::new(versions))
    }

    pub fn from_revision(revision: &str) -> Result<Self> {
        let mut versions = HashMap::new();
        let new_version =
            cargo::get_diem_node_binary_at_revision(revision).map(|(revision, bin)| {
                let version = Version::new(usize::max_value(), revision.clone());
                LocalVersion {
                    revision,
                    bin,
                    version,
                }
            })?;

        versions.insert(new_version.version.clone(), new_version);
        Ok(Self::new(versions))
    }

    pub fn with_revision_and_workspace(revision: &str) -> Result<Self> {
        let workspace = cargo::get_diem_node_binary_from_worktree().map(|(revision, bin)| {
            let version = Version::new(usize::max_value(), revision.clone());
            LocalVersion {
                revision,
                bin,
                version,
            }
        })?;
        let revision =
            cargo::get_diem_node_binary_at_revision(revision).map(|(revision, bin)| {
                let version = Version::new(usize::min_value(), revision.clone());
                LocalVersion {
                    revision,
                    bin,
                    version,
                }
            })?;

        let mut versions = HashMap::new();
        versions.insert(workspace.version(), workspace);
        versions.insert(revision.version(), revision);
        Ok(Self::new(versions))
    }

    /// Create a LocalFactory with a diem-node version built at the tip of upstream/main and the
    /// current workspace, suitable for compatibility testing.
    pub fn with_upstream_and_workspace() -> Result<Self> {
        let upstream_main = cargo::git_get_upstream_remote().map(|r| format!("{}/main", r))?;
        Self::with_revision_and_workspace(&upstream_main)
    }

    /// Create a LocalFactory with a diem-node version built at merge-base of upstream/main and the
    /// current workspace, suitable for compatibility testing.
    pub fn with_upstream_merge_base_and_workspace() -> Result<Self> {
        let upstream_main = cargo::git_get_upstream_remote().map(|r| format!("{}/main", r))?;
        let merge_base = cargo::git_merge_base(upstream_main)?;
        Self::with_revision_and_workspace(&merge_base)
    }
}

impl Factory for LocalFactory {
    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        Box::new(self.versions.keys().cloned())
    }

    fn launch_swarm(
        &self,
        rng: &mut StdRng,
        node_num: NonZeroUsize,
        version: &Version,
    ) -> Result<Box<dyn Swarm>> {
        let mut swarm = LocalSwarm::builder(self.versions.clone())
            .number_of_validators(node_num)
            .initial_version(version.clone())
            .build(rng)?;
        swarm
            .launch()
            .with_context(|| format!("Swarm logs can be found here: {}", swarm.logs_location()))?;

        // swarm.launch().map_err(|e| {
        //     swarm.logs_location()
        //     e
        // });
        // match swarm.launch() {
        //     Ok(()) => {}
        //     Err(e) => {
        //         swarm.
        //         return e;
        //     }
        // }

        Ok(Box::new(swarm))
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Timing functions.
use std::time::precise_time_ns;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::os::getenv;

pub enum ProfilerCategory {
    CompositingCategory,
    LayoutPerformCategory,
    LayoutQueryCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingPrepBuffCategory,
    RenderingWaitSubtasksCategory,
    RenderingCategory,
}
static NUM_BUCKETS: uint = 12;

pub type ProfilerChan = SharedChan<(ProfilerCategory, uint)>;
pub type ProfilerPort = Port<(ProfilerCategory, uint)>;
pub struct ProfilerTask {
    chan: ProfilerChan,
}

impl ProfilerTask {
    pub fn new(prof_port: ProfilerPort,
               prof_chan: ProfilerChan)
               -> ProfilerTask {
        let prof_port = Cell(prof_port);

        do spawn {
            let mut profiler_context = ProfilerContext::new(prof_port.take());
            profiler_context.start();
        }

        ProfilerTask {
            chan: prof_chan
        }
    }
}

pub struct ProfilerContext {
    port: ProfilerPort,
    buckets: [~[uint], ..NUM_BUCKETS],
    verbose: Option<~str>,
    mut last_print: u64,
}

impl ProfilerContext {
    pub fn new(port: ProfilerPort) -> ProfilerContext {
        ProfilerContext {
            port: port,
            buckets: [~[], ..NUM_BUCKETS],
            verbose: getenv("SERVO_PROFILER"),
            last_print: 0,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.recv();
            self.handle_msg(msg);
        }
    }

    priv fn handle_msg(&mut self, msg: (ProfilerCategory, uint)) {
        let (prof_msg, t) = msg;
        self.buckets[prof_msg as uint].push(t);
        if self.verbose.is_some() {
            let cur_time = precise_time_ns() / 1000000000u64;
            if cur_time - self.last_print > 5 {
                self.last_print = cur_time;
                let mut i = 0;
                for self.buckets.each |bucket| {
                    let prof_msg = match i {
                        0 => CompositingCategory,
                        1 => LayoutPerformCategory,
                        2 => LayoutQueryCategory,
                        3 => LayoutAuxInitCategory,
                        4 => LayoutSelectorMatchCategory,
                        5 => LayoutTreeBuilderCategory,
                        6 => LayoutMainCategory,
                        7 => LayoutDispListBuildCategory,
                        8 => GfxRegenAvailableFontsCategory,
                        9 => RenderingPrepBuffCategory,
                        10 => RenderingWaitSubtasksCategory,
                        11 => RenderingCategory,
                        _ => fail!()
                    };
                    io::println(fmt!("%?: %f", prof_msg,
                                 (bucket.foldl(0 as uint, |a, b| a + *b) as float) /
                                 (bucket.len() as float)));
                    i += 1;
                }
                io::println("");
            }
        }

    }
}

pub fn profile<T>(cat: ProfilerCategory,
                  prof_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) / 1000000u64) as uint;
    prof_chan.send((cat, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) / 1000000u64) as uint;
    if ms >= 5 {
        debug!("%s took %u ms", msg, ms);
    }
    return val;
}

<commit_msg>comment on updating NUM_BUCKETS in time.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Timing functions.
use std::time::precise_time_ns;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::os::getenv;

pub enum ProfilerCategory {
    CompositingCategory,
    LayoutPerformCategory,
    LayoutQueryCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingPrepBuffCategory,
    RenderingWaitSubtasksCategory,
    RenderingCategory,
}
// change this whenever buckets are added/rm'd
static NUM_BUCKETS: uint = 12;

pub type ProfilerChan = SharedChan<(ProfilerCategory, uint)>;
pub type ProfilerPort = Port<(ProfilerCategory, uint)>;
pub struct ProfilerTask {
    chan: ProfilerChan,
}

impl ProfilerTask {
    pub fn new(prof_port: ProfilerPort,
               prof_chan: ProfilerChan)
               -> ProfilerTask {
        let prof_port = Cell(prof_port);

        do spawn {
            let mut profiler_context = ProfilerContext::new(prof_port.take());
            profiler_context.start();
        }

        ProfilerTask {
            chan: prof_chan
        }
    }
}

pub struct ProfilerContext {
    port: ProfilerPort,
    buckets: [~[uint], ..NUM_BUCKETS],
    verbose: Option<~str>,
    mut last_print: u64,
}

impl ProfilerContext {
    pub fn new(port: ProfilerPort) -> ProfilerContext {
        ProfilerContext {
            port: port,
            buckets: [~[], ..NUM_BUCKETS],
            verbose: getenv("SERVO_PROFILER"),
            last_print: 0,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.recv();
            self.handle_msg(msg);
        }
    }

    priv fn handle_msg(&mut self, msg: (ProfilerCategory, uint)) {
        let (prof_msg, t) = msg;
        self.buckets[prof_msg as uint].push(t);
        if self.verbose.is_some() {
            let cur_time = precise_time_ns() / 1000000000u64;
            if cur_time - self.last_print > 5 {
                self.last_print = cur_time;
                let mut i = 0;
                for self.buckets.each |bucket| {
                    let prof_msg = match i {
                        // must be in same order as ProfilerCategory
                        0 => CompositingCategory,
                        1 => LayoutPerformCategory,
                        2 => LayoutQueryCategory,
                        3 => LayoutAuxInitCategory,
                        4 => LayoutSelectorMatchCategory,
                        5 => LayoutTreeBuilderCategory,
                        6 => LayoutMainCategory,
                        7 => LayoutDispListBuildCategory,
                        8 => GfxRegenAvailableFontsCategory,
                        9 => RenderingPrepBuffCategory,
                        10 => RenderingWaitSubtasksCategory,
                        11 => RenderingCategory,
                        _ => fail!()
                    };
                    io::println(fmt!("%?: %f", prof_msg,
                                 (bucket.foldl(0 as uint, |a, b| a + *b) as float) /
                                 (bucket.len() as float)));
                    i += 1;
                }
                io::println("");
            }
        }

    }
}

pub fn profile<T>(cat: ProfilerCategory,
                  prof_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) / 1000000u64) as uint;
    prof_chan.send((cat, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) / 1000000u64) as uint;
    if ms >= 5 {
        debug!("%s took %u ms", msg, ms);
    }
    return val;
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate sputnikvm;
extern crate bigint;
extern crate serde_json;
extern crate gethrpc;

use serde_json::{Value};
use std::process;
use std::fs::File;
use std::path::Path;
use std::io::{BufReader};
use std::str::FromStr;

use sputnikvm::{Gas, Address};
use bigint::{U256, M256, read_hex};
use sputnikvm::vm::{BlockHeader, Context, VM};
use gethrpc::{regression, GethRPCClient, RPCCall, RPCBlock, RPCTransaction};

fn from_rpc_block(block: &RPCBlock) -> BlockHeader {
    BlockHeader {
        coinbase: Address::from_str(&block.miner).unwrap(),
        timestamp: M256::from_str(&block.timestamp).unwrap(),
        number: M256::from_str(&block.number).unwrap(),
        difficulty: M256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction_and_code(transaction: &RPCTransaction, code: &str) -> Context {
    Context {
        caller: Address::from_str(&transaction.from).unwrap(),
        address: Address::from_str(&transaction.to).unwrap(),
        origin: Address::from_str(&transaction.to).unwrap(),
        value: U256::from_str(&transaction.value).unwrap(),
        code: read_hex(code).unwrap(),
        data: read_hex(&transaction.input).unwrap(),
        gas_limit: Gas::from_str(&transaction.gas).unwrap(),
        gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
    }
}

fn main() {
    let mut client = GethRPCClient::new("http://127.0.0.1:8545");

    println!("net version: {}", client.net_version());

    let block = client.get_block_by_number(format!("0x{:x}", 49439).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());

    let block_header = from_rpc_block(&block);
    println!("block header: {:?}", block_header);

    for transaction_hash in block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = client.get_transaction_by_hash(&transaction_hash);
        println!("transaction: {:?}", transaction);
        let receipt = client.get_transaction_receipt(&transaction_hash);
        println!("receipt: {:?}", receipt);
        let code = client.get_code(&transaction.to, &block.number);
        println!("code: {:?}", code);

        let context = from_rpc_transaction_and_code(&transaction, &code);
        println!("context: {:?}", context);

        println!("\ntests after the vm has run:");
        println!("2. test gasUsed == {:?}", receipt.gasUsed);
        println!("3. logs and order is {:?}", receipt.logs);
    }

    println!("\nwhen the block is finished, test:");
    println!("1. balances of all used accounts.");
    println!("2. storage values touched.");

    // let matches = clap_app!(regression_test =>
    //     (version: "0.1")
    //     (author: "Ethereum Classic Contributors")
    //     (about: "Gaslighter - Tests the Ethereum Classic Virtual Machine in 5 different ways.")
    //     (@arg KEEP_GOING: -k --keep_going "Don't exit the program even if a test fails.")
    //     (@subcommand reg =>
    //         (about: "Performs an regression test on the entire Ethereum Classic blockchain.\n\nSteps to reproduce:\n* Install Ethereum Classic Geth: `$ go install github.com/ethereumproject/go-ethereum/cmd/geth`.\n* Run Geth with this command: `$ ~/go/bin/geth`.\n* Wait for the chain to sync.\n* <ctrl-c>\n* Change directory into the gaslighter directory `$ cd gaslighter`\n* Run this command: `$ RUST_BACKTRACE=1 RUST_LOG=gaslighter cargo run --bin gaslighter -- -k reg -c ~/.ethereum/chaindata/`")
    //         (@arg RPC: -r --rpc +takes_value +required "Domain of Ethereum Classic Geth's RPC endpoint. e.g. `-r localhost:8888`.")
    //     )
    // ).get_matches();
    // let mut has_regression_test_passed = true;
    // let keep_going = if matches.is_present("KEEP_GOING") { true } else { false };
    // if let Some(ref matches) = matches.subcommand_matches("reg") {
    //     let path = matches.value_of("RPC").unwrap();
    //     has_regression_test_passed = regression(path);
    // }
    // if has_regression_test_passed {
    //     process::exit(0);
    // } else {
    //     process::exit(1);
    // }
}
<commit_msg>Problem: missing VM fire in test<commit_after>#[macro_use]
extern crate clap;
extern crate sputnikvm;
extern crate bigint;
extern crate serde_json;
extern crate gethrpc;

use serde_json::{Value};
use std::process;
use std::fs::File;
use std::path::Path;
use std::io::{BufReader};
use std::str::FromStr;

use sputnikvm::{Gas, Address};
use bigint::{U256, M256, read_hex};
use sputnikvm::vm::{BlockHeader, Context, SeqVM, Patch};
use gethrpc::{regression, GethRPCClient, RPCCall, RPCBlock, RPCTransaction};

fn from_rpc_block(block: &RPCBlock) -> BlockHeader {
    BlockHeader {
        coinbase: Address::from_str(&block.miner).unwrap(),
        timestamp: M256::from_str(&block.timestamp).unwrap(),
        number: M256::from_str(&block.number).unwrap(),
        difficulty: M256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction_and_code(transaction: &RPCTransaction, code: &str) -> Context {
    Context {
        caller: Address::from_str(&transaction.from).unwrap(),
        address: Address::from_str(&transaction.to).unwrap(),
        origin: Address::from_str(&transaction.to).unwrap(),
        value: U256::from_str(&transaction.value).unwrap(),
        code: read_hex(code).unwrap(),
        data: read_hex(&transaction.input).unwrap(),
        gas_limit: Gas::from_str(&transaction.gas).unwrap(),
        gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
    }
}

fn main() {
    let mut client = GethRPCClient::new("http://127.0.0.1:8545");

    println!("net version: {}", client.net_version());

    let block = client.get_block_by_number(format!("0x{:x}", 49439).as_str());
    println!("block {}, transaction count: {}", block.number, block.transactions.len());

    let block_header = from_rpc_block(&block);
    println!("block header: {:?}", block_header);

    for transaction_hash in block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = client.get_transaction_by_hash(&transaction_hash);
        println!("transaction: {:?}", transaction);
        let receipt = client.get_transaction_receipt(&transaction_hash);
        println!("receipt: {:?}", receipt);
        let code = client.get_code(&transaction.to, &block.number);
        println!("code: {:?}", code);

        let context = from_rpc_transaction_and_code(&transaction, &code);
        println!("context: {:?}", context);

        let mut vm = SeqVM::new(context, block_header.clone(), Patch::empty());
        loop {
            match vm.fire() {
                Ok(()) => {
                    println!("VM exited successfully, checking results ...");
                    break;
                },
                Err(err) => {
                    println!("Unhandled require: {:?}", err);
                    unimplemented!()
                },
            }
        }

        println!("\ntests after the vm has run:");
        println!("2. test gasUsed == {:?}", receipt.gasUsed);
        println!("3. logs and order is {:?}", receipt.logs);
    }

    println!("\nwhen the block is finished, test:");
    println!("1. balances of all used accounts.");
    println!("2. storage values touched.");

    // let matches = clap_app!(regression_test =>
    //     (version: "0.1")
    //     (author: "Ethereum Classic Contributors")
    //     (about: "Gaslighter - Tests the Ethereum Classic Virtual Machine in 5 different ways.")
    //     (@arg KEEP_GOING: -k --keep_going "Don't exit the program even if a test fails.")
    //     (@subcommand reg =>
    //         (about: "Performs an regression test on the entire Ethereum Classic blockchain.\n\nSteps to reproduce:\n* Install Ethereum Classic Geth: `$ go install github.com/ethereumproject/go-ethereum/cmd/geth`.\n* Run Geth with this command: `$ ~/go/bin/geth`.\n* Wait for the chain to sync.\n* <ctrl-c>\n* Change directory into the gaslighter directory `$ cd gaslighter`\n* Run this command: `$ RUST_BACKTRACE=1 RUST_LOG=gaslighter cargo run --bin gaslighter -- -k reg -c ~/.ethereum/chaindata/`")
    //         (@arg RPC: -r --rpc +takes_value +required "Domain of Ethereum Classic Geth's RPC endpoint. e.g. `-r localhost:8888`.")
    //     )
    // ).get_matches();
    // let mut has_regression_test_passed = true;
    // let keep_going = if matches.is_present("KEEP_GOING") { true } else { false };
    // if let Some(ref matches) = matches.subcommand_matches("reg") {
    //     let path = matches.value_of("RPC").unwrap();
    //     has_regression_test_passed = regression(path);
    // }
    // if has_regression_test_passed {
    //     process::exit(0);
    // } else {
    //     process::exit(1);
    // }
}
<|endoftext|>


<commit_before>use std::collections::VecMap;
use std::cell::RefCell;
use std::rand;
use serialize::json;
use rand::Rng;
use calx::color;
use ecs::Ecs;
use area::Area;
use spatial::Spatial;
use flags::Flags;
use mob::{Mob, Intrinsic};
use entity::Entity;
use action;
use components::{Prototype};
use components::{Desc, Kind, MapMemory, MobStat, Spawn};
use {Biome};

thread_local!(static WORLD_STATE: RefCell<WorldState> = RefCell::new(WorldState::new(None)))

/// Access world state for reading. The world state may not be reaccessed for
/// writing while within this function.
pub fn with<A>(f: |&WorldState| -> A) -> A {
    WORLD_STATE.with(|w| f(w.borrow().deref()))
}

/// Access world state for reading and writing. The world state may not be
/// reaccessed while within this function.
pub fn with_mut<A>(f: |&mut WorldState| -> A) -> A {
    WORLD_STATE.with(|w| f(w.borrow_mut().deref_mut()))
}

/// Save the global world state into a json string.
pub fn save() -> String {
    with(|w| json::encode(w))
}

/// Load the global world state from a json string. If the load operation
/// is successful, the previous world state will be overwritten by the loaded
/// one.
pub fn load(json: &str) -> Result<(), json::DecoderError> {
    WORLD_STATE.with(|w| {
        match json::decode::<WorldState>(json) {
            Ok(ws) => {
                *w.borrow_mut() = ws;
                Ok(())
            }
            Err(e) => Err(e)
        }
    })
}

/// The internal object that holds all the world state data.
#[deriving(Encodable, Decodable)]
pub struct WorldState {
    /// Global entity handler.
    pub ecs: Ecs,
    /// World terrain generation and storage.
    pub area: Area,
    /// Spatial index for game entities.
    pub spatial: Spatial,
    /// Global gamestate flags.
    pub flags: Flags,

    comps: Comps,
}

impl<'a> WorldState {
    pub fn new(seed: Option<u32>) -> WorldState {
        let seed = match seed {
            Some(s) => s,
            // Use system rng for seed if the user didn't provide one.
            None => rand::task_rng().gen()
        };
        WorldState {
            ecs: Ecs::new(),
            area: Area::new(seed, ::AreaSpec::new(::Biome::Overland, 1)),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
            comps: Comps::new(),
        }
    }
}

/// Set up a fresh start-game world state with an optional fixed random number
/// generator seed. Calling init_world will cause any existing world state to
/// be discarded.
pub fn init_world(seed: Option<u32>) {
    WORLD_STATE.with(|w| *w.borrow_mut() = WorldState::new(seed));

    // Init the prototypes
    Prototype::new()
        (Desc { name: "Player".to_string(), icon: 51, color: color::RED })
        (MobStat { power: 6, intrinsics: Intrinsic::Hands as i32 })
        ;

    Prototype::new()
        (Desc { name: "Dreg".to_string(), icon: 72, color: color::OLIVE })
        (MobStat { power: 1, intrinsics: Intrinsic::Hands as i32 })
        (Spawn { biome: Biome::Anywhere, rarity: 10, min_depth: 1 })
        ;

    Prototype::new()
        (Desc { name: "Snake".to_string(), icon: 71, color: color::GREEN })
        (MobStat { power: 1, intrinsics: 0 })
        (Spawn { biome: Biome::Overland, rarity: 10, min_depth: 1 })
        ;

    Prototype::new()
        (Desc { name: "Ooze".to_string(), icon: 77, color: color::LIGHTSEAGREEN })
        (MobStat { power: 3, intrinsics: 0 })
        (Spawn { biome: Biome::Dungeon, rarity: 10, min_depth: 3 })
        ;

    action::start_level(1);
}

// Components stuff ////////////////////////////////////////////////////

#[deriving(Encodable, Decodable)]
struct Comps {
    descs: VecMap<Desc>,
    kinds: VecMap<Kind>,
    map_memories: VecMap<MapMemory>,
    mobs: VecMap<Mob>,
    mob_stats: VecMap<MobStat>,
    spawns: VecMap<Spawn>,
}

impl Comps {
    pub fn new() -> Comps {
        Comps {
            descs: VecMap::new(),
            kinds: VecMap::new(),
            map_memories: VecMap::new(),
            mobs: VecMap::new(),
            mob_stats: VecMap::new(),
            spawns: VecMap::new(),
        }
    }
}

macro_rules! comp_api {
    // Rust macros can't concatenate "_mut" to $name because reasons, so the
    // _mut suffix name needs to be passed in explicitly.
    { $name:ident, $name_mut:ident, $typ:ty } => {
        impl<'a> WorldState {
        pub fn $name(&'a self) -> ComponentRef<'a, $typ> {
            ComponentRef::new(&self.ecs, &self.comps.$name)
        }
        pub fn $name_mut(&'a mut self) -> ComponentRefMut<'a, $typ> {
            ComponentRefMut::new(&mut self.ecs, &mut self.comps.$name)
        }
        }
    }
}

// COMPONENTS CHECKPOINT
comp_api!(descs, descs_mut, Desc)
comp_api!(kinds, kinds_mut, Kind)
comp_api!(map_memories, map_memories_mut, MapMemory)
comp_api!(mobs, mobs_mut, Mob)
comp_api!(mob_stats, mob_stats_mut, MobStat)
comp_api!(spawns, spawns_mut, Spawn)

/// Immutable component access.
pub struct ComponentRef<'a, C: 'static> {
    ecs: &'a Ecs,
    data: &'a VecMap<C>,
}

impl<'a, C> ComponentRef<'a, C> {
    fn new(ecs: &'a Ecs, data: &'a VecMap<C>) -> ComponentRef<'a, C> {
        ComponentRef {
            ecs: ecs,
            data: data,
        }
    }

    /// Fetch a component from given entity or its parent.
    pub fn get(self, Entity(idx): Entity) -> Option<&'a C> {
        match find_parent(|Entity(idx)| self.data.contains_key(&idx), self.ecs, Entity(idx)) {
            None => { None }
            Some(Entity(idx)) => { self.data.get(&idx) }
        }
    }

    /// Fetch a component from given entity. Do not search parent entities.
    pub fn get_local(self, Entity(idx): Entity) -> Option<&'a C> {
        self.data.get(&idx)
    }
}

/// Mutable component access.
pub struct ComponentRefMut<'a, C: 'static> {
    ecs: &'a mut Ecs,
    data: &'a mut VecMap<C>,
}

impl<'a, C: Clone> ComponentRefMut<'a, C> {
    fn new(ecs: &'a mut Ecs, data: &'a mut VecMap<C>) -> ComponentRefMut<'a, C> {
        ComponentRefMut {
            ecs: ecs,
            data: data,
        }
    }

    /// Fetch a component from given entity or its parent. Copy-on-write
    /// semantics: A component found on a parent entity will be copied on
    /// local entity for mutation.
    pub fn get(self, Entity(idx): Entity) -> Option<&'a mut C> {
        match find_parent(|Entity(idx)| self.data.contains_key(&idx), self.ecs, Entity(idx)) {
            None => { None }
            Some(Entity(idx2)) if idx2 == idx => { self.data.get_mut(&idx2) }
            Some(Entity(idx2)) => {
                // Copy-on-write: Make a local copy of inherited component
                // when asking for mutable access.
                let cow = self.data.get(&idx2).unwrap().clone();
                self.data.insert(idx, cow);
                self.data.get_mut(&idx)
            }
        }
    }

    /// Add a component to entity.
    pub fn insert(self, Entity(idx): Entity, comp: C) {
        self.data.insert(idx, comp);
    }

    /// Remove a component from an entity. This will make a parent entity's
    /// component visible instead, if there is one. There is currently no way
    /// to hide components present in a parent entity.
    pub fn remove(self, Entity(idx): Entity) {
        self.data.remove(&idx);
    }
}

fn find_parent<P: Fn<(Entity,), bool>>(p: P, ecs: &Ecs, e: Entity) -> Option<Entity> {
    let mut current = e;
    loop {
        if p(current) { return Some(current); }
        match ecs.parent(current) {
            Some(parent) => { current = parent; }
            None => { return None; }
        }
    }
}
<commit_msg>Spawn player with map memory<commit_after>use std::collections::VecMap;
use std::cell::RefCell;
use std::rand;
use serialize::json;
use rand::Rng;
use calx::color;
use ecs::Ecs;
use area::Area;
use spatial::Spatial;
use flags::Flags;
use mob::{Mob, Intrinsic};
use entity::Entity;
use action;
use components::{Prototype};
use components::{Desc, Kind, MapMemory, MobStat, Spawn};
use {Biome};

thread_local!(static WORLD_STATE: RefCell<WorldState> = RefCell::new(WorldState::new(None)))

/// Access world state for reading. The world state may not be reaccessed for
/// writing while within this function.
pub fn with<A>(f: |&WorldState| -> A) -> A {
    WORLD_STATE.with(|w| f(w.borrow().deref()))
}

/// Access world state for reading and writing. The world state may not be
/// reaccessed while within this function.
pub fn with_mut<A>(f: |&mut WorldState| -> A) -> A {
    WORLD_STATE.with(|w| f(w.borrow_mut().deref_mut()))
}

/// Save the global world state into a json string.
pub fn save() -> String {
    with(|w| json::encode(w))
}

/// Load the global world state from a json string. If the load operation
/// is successful, the previous world state will be overwritten by the loaded
/// one.
pub fn load(json: &str) -> Result<(), json::DecoderError> {
    WORLD_STATE.with(|w| {
        match json::decode::<WorldState>(json) {
            Ok(ws) => {
                *w.borrow_mut() = ws;
                Ok(())
            }
            Err(e) => Err(e)
        }
    })
}

/// The internal object that holds all the world state data.
#[deriving(Encodable, Decodable)]
pub struct WorldState {
    /// Global entity handler.
    pub ecs: Ecs,
    /// World terrain generation and storage.
    pub area: Area,
    /// Spatial index for game entities.
    pub spatial: Spatial,
    /// Global gamestate flags.
    pub flags: Flags,

    comps: Comps,
}

impl<'a> WorldState {
    pub fn new(seed: Option<u32>) -> WorldState {
        let seed = match seed {
            Some(s) => s,
            // Use system rng for seed if the user didn't provide one.
            None => rand::task_rng().gen()
        };
        WorldState {
            ecs: Ecs::new(),
            area: Area::new(seed, ::AreaSpec::new(::Biome::Overland, 1)),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
            comps: Comps::new(),
        }
    }
}

/// Set up a fresh start-game world state with an optional fixed random number
/// generator seed. Calling init_world will cause any existing world state to
/// be discarded.
pub fn init_world(seed: Option<u32>) {
    WORLD_STATE.with(|w| *w.borrow_mut() = WorldState::new(seed));

    // Init the prototypes
    Prototype::new()
        (Desc { name: "Player".to_string(), icon: 51, color: color::RED })
        (MobStat { power: 6, intrinsics: Intrinsic::Hands as i32 })
        (MapMemory::new())
        ;

    Prototype::new()
        (Desc { name: "Dreg".to_string(), icon: 72, color: color::OLIVE })
        (MobStat { power: 1, intrinsics: Intrinsic::Hands as i32 })
        (Spawn { biome: Biome::Anywhere, rarity: 10, min_depth: 1 })
        ;

    Prototype::new()
        (Desc { name: "Snake".to_string(), icon: 71, color: color::GREEN })
        (MobStat { power: 1, intrinsics: 0 })
        (Spawn { biome: Biome::Overland, rarity: 10, min_depth: 1 })
        ;

    Prototype::new()
        (Desc { name: "Ooze".to_string(), icon: 77, color: color::LIGHTSEAGREEN })
        (MobStat { power: 3, intrinsics: 0 })
        (Spawn { biome: Biome::Dungeon, rarity: 10, min_depth: 3 })
        ;

    action::start_level(1);
}

// Components stuff ////////////////////////////////////////////////////

#[deriving(Encodable, Decodable)]
struct Comps {
    descs: VecMap<Desc>,
    kinds: VecMap<Kind>,
    map_memories: VecMap<MapMemory>,
    mobs: VecMap<Mob>,
    mob_stats: VecMap<MobStat>,
    spawns: VecMap<Spawn>,
}

impl Comps {
    pub fn new() -> Comps {
        Comps {
            descs: VecMap::new(),
            kinds: VecMap::new(),
            map_memories: VecMap::new(),
            mobs: VecMap::new(),
            mob_stats: VecMap::new(),
            spawns: VecMap::new(),
        }
    }
}

macro_rules! comp_api {
    // Rust macros can't concatenate "_mut" to $name because reasons, so the
    // _mut suffix name needs to be passed in explicitly.
    { $name:ident, $name_mut:ident, $typ:ty } => {
        impl<'a> WorldState {
        pub fn $name(&'a self) -> ComponentRef<'a, $typ> {
            ComponentRef::new(&self.ecs, &self.comps.$name)
        }
        pub fn $name_mut(&'a mut self) -> ComponentRefMut<'a, $typ> {
            ComponentRefMut::new(&mut self.ecs, &mut self.comps.$name)
        }
        }
    }
}

// COMPONENTS CHECKPOINT
comp_api!(descs, descs_mut, Desc)
comp_api!(kinds, kinds_mut, Kind)
comp_api!(map_memories, map_memories_mut, MapMemory)
comp_api!(mobs, mobs_mut, Mob)
comp_api!(mob_stats, mob_stats_mut, MobStat)
comp_api!(spawns, spawns_mut, Spawn)

/// Immutable component access.
pub struct ComponentRef<'a, C: 'static> {
    ecs: &'a Ecs,
    data: &'a VecMap<C>,
}

impl<'a, C> ComponentRef<'a, C> {
    fn new(ecs: &'a Ecs, data: &'a VecMap<C>) -> ComponentRef<'a, C> {
        ComponentRef {
            ecs: ecs,
            data: data,
        }
    }

    /// Fetch a component from given entity or its parent.
    pub fn get(self, Entity(idx): Entity) -> Option<&'a C> {
        match find_parent(|Entity(idx)| self.data.contains_key(&idx), self.ecs, Entity(idx)) {
            None => { None }
            Some(Entity(idx)) => { self.data.get(&idx) }
        }
    }

    /// Fetch a component from given entity. Do not search parent entities.
    pub fn get_local(self, Entity(idx): Entity) -> Option<&'a C> {
        self.data.get(&idx)
    }
}

/// Mutable component access.
pub struct ComponentRefMut<'a, C: 'static> {
    ecs: &'a mut Ecs,
    data: &'a mut VecMap<C>,
}

impl<'a, C: Clone> ComponentRefMut<'a, C> {
    fn new(ecs: &'a mut Ecs, data: &'a mut VecMap<C>) -> ComponentRefMut<'a, C> {
        ComponentRefMut {
            ecs: ecs,
            data: data,
        }
    }

    /// Fetch a component from given entity or its parent. Copy-on-write
    /// semantics: A component found on a parent entity will be copied on
    /// local entity for mutation.
    pub fn get(self, Entity(idx): Entity) -> Option<&'a mut C> {
        match find_parent(|Entity(idx)| self.data.contains_key(&idx), self.ecs, Entity(idx)) {
            None => { None }
            Some(Entity(idx2)) if idx2 == idx => { self.data.get_mut(&idx2) }
            Some(Entity(idx2)) => {
                // Copy-on-write: Make a local copy of inherited component
                // when asking for mutable access.
                let cow = self.data.get(&idx2).unwrap().clone();
                self.data.insert(idx, cow);
                self.data.get_mut(&idx)
            }
        }
    }

    /// Add a component to entity.
    pub fn insert(self, Entity(idx): Entity, comp: C) {
        self.data.insert(idx, comp);
    }

    /// Remove a component from an entity. This will make a parent entity's
    /// component visible instead, if there is one. There is currently no way
    /// to hide components present in a parent entity.
    pub fn remove(self, Entity(idx): Entity) {
        self.data.remove(&idx);
    }
}

fn find_parent<P: Fn<(Entity,), bool>>(p: P, ecs: &Ecs, e: Entity) -> Option<Entity> {
    let mut current = e;
    loop {
        if p(current) { return Some(current); }
        match ecs.parent(current) {
            Some(parent) => { current = parent; }
            None => { return None; }
        }
    }
}
<|endoftext|>