<commit_before>//! ### TODO
//!
//! * Clarify terminology (to wire, to load, option, alternative, option).
//! * Single alternative options are a _special case_ of options/alternatives.
//!   To avoid confusion, all code & doc related to single alternative options
//!   should be listed after regular options/alternatives.

#![feature(get_type_id)]
#![feature(box_syntax)]

#[macro_use] extern crate qdowncast;
extern crate qindex_multi;

#[macro_use] mod macros;

use qdowncast::QDowncastable;
use qindex_multi::MultiIndexable;

use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::ops::{Deref, DerefMut, Index, IndexMut};

// ++++++++++++++++++++ OptionReflect ++++++++++++++++++++

/// Our `Reflect`-derivative.
/// This supplies necessary information for retrieving an object at compile-time.
pub trait OptionReflect: Any {
    fn option_name() -> &'static str;
}

// ++++++++++++++++++++ GetObjectError ++++++++++++++++++++

#[derive(Debug, Clone)]
pub enum GetObjectError<'a> {
    TypeMismatch{ option_name: &'a str, expected: TypeId, found: TypeId },
    MissingOption(&'a str),
}

impl<'a> GetObjectError<'a> {
    pub fn type_mismatch<Expected>(found: TypeId) -> GetObjectError<'static>
        where Expected: OptionReflect
    {
        GetObjectError::TypeMismatch{
            option_name: Expected::option_name(),
            expected: TypeId::of::<Expected>(),
            found: found,
        }
    }
}

pub type GetObjectResult<'a, T> = Result<T, GetObjectError<'a>>;

// ++++++++++++++++++++ Entry ++++++++++++++++++++

/// TODO expose this to the user?
enum Entry<Obj: Any + ?Sized> {
    /// A single alternative option. Is always wired to exactly one object.
    Single(Box<Obj>),

    /// A option with zero or more alternatives. May be wired to one of its objects.
    Multi{
        wired: Option<usize>,
        alternatives: Vec<(String, Box<Obj>)>,
    }
}

impl<Obj: Any + ?Sized> Entry<Obj> {
    fn has_alternative(&self, alt_name: &str) -> bool {
        match self {
            &Entry::Multi{ ref alternatives, .. } => {
                alternatives.iter().any(|e| &*e.0 == alt_name)
            }
            _ => false,
        }
    }

    fn add_alternative(&mut self, alt_name: String, obj: Box<Obj>){
        assert!(!self.has_alternative(&alt_name),
                "Alternative '{}' already exists,", alt_name);

        match self {
            &mut Entry::Multi{ ref mut alternatives, .. } => {
                alternatives.push((alt_name, obj));
            }
            _ => {
                panic!("Can't add alternative '{}' to single alternative option", alt_name);
            }
        }
    }

    fn wire_alternative(&mut self, alt_name: &str) {
        assert!(self.has_alternative(&alt_name),
                "Can't wire missing alternative '{}'", alt_name);

        match self {
            &mut Entry::Multi{ ref mut wired, ref alternatives } => {
                *wired = Some(alternatives.iter().position(|e| &*e.0 == alt_name).unwrap());
            }
            _ => { unreachable!() }
        }
    }

    fn object_ref(&self) -> Option<&Obj> {
        match self {
            &Entry::Single(ref obj) => Some(&**obj),
            &Entry::Multi{ wired, ref alternatives } => match wired {
                Some(idx) => Some(&*alternatives[idx].1),
                None => None,
            }
        }
    }

    fn object_mut(&mut self) -> Option<&mut Obj> {
        match self {
            &mut Entry::Single(ref mut obj) => Some(&mut**obj),
            &mut Entry::Multi{ wired, ref mut alternatives } => match wired {
                Some(idx) => Some(&mut*alternatives[idx].1),
                None => None,
            }
        }
    }
}

// ++++++++++++++++++++ Register ++++++++++++++++++++

pub trait DefaultBase: Any {}
impl<T: Any + ?Sized> DefaultBase for T {}

pub struct Register<Obj: Any + ?Sized = DefaultBase> {
    entrys: BTreeMap<String, Entry<Obj>>,
}

impl<Obj: Any + ?Sized> Register<Obj> {

    /// Try to get the object wired to option `opt_name` immutably.
    pub fn get_object(&self, opt_name: &str) -> Option<&Obj> {
        self.entrys.get(opt_name).and_then(|entry| entry.object_ref())
    }

    /// Try to get the object wired to option `opt_name` mutably.
    pub fn get_object_mut(&mut self, opt_name: &str) -> Option<&mut Obj> {
        self.entrys.get_mut(opt_name).and_then(|entry| entry.object_mut())
    }

    pub fn get<T>(&self) -> GetObjectResult<&T>
        where T: OptionReflect, Obj: QDowncastable<T>
    {
        match self.get_object(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_ref(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetObjectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetObjectError::MissingOption(T::option_name()))
        }
    }

    pub fn get_mut<T>(&mut self) -> GetObjectResult<&mut T>
        where T: OptionReflect, Obj: QDowncastable<T>
    {
        match self.get_object_mut(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_mut(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetObjectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetObjectError::MissingOption(T::option_name()))
        }
    }

    pub fn iter(&self) -> Iter<Obj> {
        Iter{ entrys: self.entrys.iter() }
    }
    pub fn iter_mut(&mut self) -> IterMut<Obj> {
        IterMut{ entrys: self.entrys.iter_mut() }
    }
}

#[derive(Clone)]
pub struct Iter<'a, Obj: Any + ?Sized = DefaultBase> {
    entrys: btree_map::Iter<'a, String, Entry<Obj>>,
}

impl<'a, Obj: Any + ?Sized> Iterator for Iter<'a, Obj> {
    type Item = (&'a str, &'a Obj);
    fn next(&mut self) -> Option<Self::Item> {
        match self.entrys.next() {
            Some((opt_name, entry)) => match entry.object_ref() {
                Some(obj) => Some((&opt_name, obj)),
                None => self.next(),
            },
            None => None,
        }
    }
}

pub struct IterMut<'a, Obj: Any + ?Sized = DefaultBase> {
    entrys: btree_map::IterMut<'a, String, Entry<Obj>>,
}

impl<'a, Obj: Any + ?Sized> Iterator for IterMut<'a, Obj> {
    type Item = (&'a str, &'a mut Obj);
    fn next(&mut self) -> Option<Self::Item> {
        match self.entrys.next() {
            Some((opt_name, entry)) => match entry.object_mut() {
                Some(obj) => Some((&opt_name, obj)),
                None => self.next(),
            },
            None => None,
        }
    }
}

impl<'a, Obj: Any + ?Sized> IntoIterator for &'a Register<Obj> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Iter<'a, Obj>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<'a, Obj: Any + ?Sized> IntoIterator for &'a mut Register<Obj> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = IterMut<'a, Obj>;
    fn into_iter(self) -> Self::IntoIter { self.iter_mut() }
}

impl<'a, Str, Obj: ?Sized> Index<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{
    type Output = Obj;
    fn index(&self, name: &'a Str) -> &Self::Output {
        self.get_object(name.borrow()).unwrap()
    }
}

impl<'a, Str, Obj: ?Sized> IndexMut<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{
    fn index_mut(&mut self, name: &'a Str) -> &mut Self::Output {
        self.get_object_mut(name.borrow()).unwrap()
    }
}

unsafe impl<'a, Str, Obj: ?Sized> MultiIndexable<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{}

// ++++++++++++++++++++ RegisterModifier ++++++++++++++++++++

pub struct RegisterModifier<Obj: Any + ?Sized = DefaultBase>(Register<Obj>);

impl<Obj: Any + ?Sized> Deref for RegisterModifier<Obj> {
    type Target = Register<Obj>;
    fn deref(&self) -> &Self::Target { &self.0 }
}
impl<Obj: Any + ?Sized> DerefMut for RegisterModifier<Obj> {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

// TODO: remove duplicated code
impl<Obj: Any + ?Sized> RegisterModifier<Obj> {
    pub fn new() -> RegisterModifier<Obj> {
        RegisterModifier(Register{ entrys: BTreeMap::new() })
    }

    pub fn unwrap(self) -> Register<Obj> { self.0 }

    pub fn add_single(&mut self, name: String, obj: Box<Obj>){
        assert!(self.entrys.contains_key(&name), "Option '{}' already exists!", &name);

        self.entrys.insert(name, Entry::Single(obj));
    }

    pub fn add_option(&mut self, name: String){
        assert!(self.entrys.contains_key(&name), "Option '{}' already exists!", &name);

        self.entrys.insert(name, Entry::Multi{
            wired: None, alternatives: Vec::new()
        });
    }

    pub fn add_alternative(&mut self, opt_name: &str, alt_name: String, obj: Box<Obj>){
        let entry = self.entrys.get_mut(opt_name);
        let entry = entry.expect(&format!("Option '{}' doesn't exist", &opt_name));

        entry.add_alternative(alt_name, obj);
    }

    pub fn wire_alternative(&mut self, opt_name: &str, alt_name: &str){
        let entry = self.entrys.get_mut(opt_name);
        let entry = entry.expect(&format!("Option '{}' doesn't exist", &opt_name));

        entry.wire_alternative(alt_name);
    }
}

<commit_msg>impl qdowncastable for DefaultBase<commit_after>//! ### TODO
//!
//! * Clarify terminology (to wire, to load, option, alternative, option).
//! * Single alternative options are a _special case_ of options/alternatives.
//!   To avoid confusion, all code & doc related to single alternative options
//!   should be listed after regular options/alternatives.

#![feature(get_type_id)]
#![feature(box_syntax)]

#[macro_use] extern crate qdowncast;
extern crate qindex_multi;

#[macro_use] mod macros;

use qdowncast::QDowncastable;
use qindex_multi::MultiIndexable;

use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::ops::{Deref, DerefMut, Index, IndexMut};

// ++++++++++++++++++++ OptionReflect ++++++++++++++++++++

/// Our `Reflect`-derivative.
/// This supplies necessary information for retrieving an object at compile-time.
pub trait OptionReflect: Any {
    fn option_name() -> &'static str;
}

// ++++++++++++++++++++ GetObjectError ++++++++++++++++++++

#[derive(Debug, Clone)]
pub enum GetObjectError<'a> {
    TypeMismatch{ option_name: &'a str, expected: TypeId, found: TypeId },
    MissingOption(&'a str),
}

impl<'a> GetObjectError<'a> {
    pub fn type_mismatch<Expected>(found: TypeId) -> GetObjectError<'static>
        where Expected: OptionReflect
    {
        GetObjectError::TypeMismatch{
            option_name: Expected::option_name(),
            expected: TypeId::of::<Expected>(),
            found: found,
        }
    }
}

pub type GetObjectResult<'a, T> = Result<T, GetObjectError<'a>>;

// ++++++++++++++++++++ Entry ++++++++++++++++++++

/// TODO expose this to the user?
enum Entry<Obj: Any + ?Sized> {
    /// A single alternative option. Is always wired to exactly one object.
    Single(Box<Obj>),

    /// A option with zero or more alternatives. May be wired to one of its objects.
    Multi{
        wired: Option<usize>,
        alternatives: Vec<(String, Box<Obj>)>,
    }
}

impl<Obj: Any + ?Sized> Entry<Obj> {
    fn has_alternative(&self, alt_name: &str) -> bool {
        match self {
            &Entry::Multi{ ref alternatives, .. } => {
                alternatives.iter().any(|e| &*e.0 == alt_name)
            }
            _ => false,
        }
    }

    fn add_alternative(&mut self, alt_name: String, obj: Box<Obj>){
        assert!(!self.has_alternative(&alt_name),
                "Alternative '{}' already exists,", alt_name);

        match self {
            &mut Entry::Multi{ ref mut alternatives, .. } => {
                alternatives.push((alt_name, obj));
            }
            _ => {
                panic!("Can't add alternative '{}' to single alternative option", alt_name);
            }
        }
    }

    fn wire_alternative(&mut self, alt_name: &str) {
        assert!(self.has_alternative(&alt_name),
                "Can't wire missing alternative '{}'", alt_name);

        match self {
            &mut Entry::Multi{ ref mut wired, ref alternatives } => {
                *wired = Some(alternatives.iter().position(|e| &*e.0 == alt_name).unwrap());
            }
            _ => { unreachable!() }
        }
    }

    fn object_ref(&self) -> Option<&Obj> {
        match self {
            &Entry::Single(ref obj) => Some(&**obj),
            &Entry::Multi{ wired, ref alternatives } => match wired {
                Some(idx) => Some(&*alternatives[idx].1),
                None => None,
            }
        }
    }

    fn object_mut(&mut self) -> Option<&mut Obj> {
        match self {
            &mut Entry::Single(ref mut obj) => Some(&mut**obj),
            &mut Entry::Multi{ wired, ref mut alternatives } => match wired {
                Some(idx) => Some(&mut*alternatives[idx].1),
                None => None,
            }
        }
    }
}

// ++++++++++++++++++++ Register ++++++++++++++++++++

pub trait DefaultBase: Any {}
impl<T: Any + ?Sized> DefaultBase for T {}
qdowncastable!(DefaultBase);
qdowncast_methods!(DefaultBase);

pub struct Register<Obj: Any + ?Sized = DefaultBase> {
    entrys: BTreeMap<String, Entry<Obj>>,
}

impl<Obj: Any + ?Sized> Register<Obj> {

    /// Try to get the object wired to option `opt_name` immutably.
    pub fn get_object(&self, opt_name: &str) -> Option<&Obj> {
        self.entrys.get(opt_name).and_then(|entry| entry.object_ref())
    }

    /// Try to get the object wired to option `opt_name` mutably.
    pub fn get_object_mut(&mut self, opt_name: &str) -> Option<&mut Obj> {
        self.entrys.get_mut(opt_name).and_then(|entry| entry.object_mut())
    }

    pub fn get<T>(&self) -> GetObjectResult<&T>
        where T: OptionReflect, Obj: QDowncastable<T>
    {
        match self.get_object(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_ref(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetObjectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetObjectError::MissingOption(T::option_name()))
        }
    }

    pub fn get_mut<T>(&mut self) -> GetObjectResult<&mut T>
        where T: OptionReflect, Obj: QDowncastable<T>
    {
        match self.get_object_mut(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_mut(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetObjectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetObjectError::MissingOption(T::option_name()))
        }
    }

    pub fn iter(&self) -> Iter<Obj> {
        Iter{ entrys: self.entrys.iter() }
    }
    pub fn iter_mut(&mut self) -> IterMut<Obj> {
        IterMut{ entrys: self.entrys.iter_mut() }
    }
}

#[derive(Clone)]
pub struct Iter<'a, Obj: Any + ?Sized = DefaultBase> {
    entrys: btree_map::Iter<'a, String, Entry<Obj>>,
}

impl<'a, Obj: Any + ?Sized> Iterator for Iter<'a, Obj> {
    type Item = (&'a str, &'a Obj);
    fn next(&mut self) -> Option<Self::Item> {
        match self.entrys.next() {
            Some((opt_name, entry)) => match entry.object_ref() {
                Some(obj) => Some((&opt_name, obj)),
                None => self.next(),
            },
            None => None,
        }
    }
}

pub struct IterMut<'a, Obj: Any + ?Sized = DefaultBase> {
    entrys: btree_map::IterMut<'a, String, Entry<Obj>>,
}

impl<'a, Obj: Any + ?Sized> Iterator for IterMut<'a, Obj> {
    type Item = (&'a str, &'a mut Obj);
    fn next(&mut self) -> Option<Self::Item> {
        match self.entrys.next() {
            Some((opt_name, entry)) => match entry.object_mut() {
                Some(obj) => Some((&opt_name, obj)),
                None => self.next(),
            },
            None => None,
        }
    }
}

impl<'a, Obj: Any + ?Sized> IntoIterator for &'a Register<Obj> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Iter<'a, Obj>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<'a, Obj: Any + ?Sized> IntoIterator for &'a mut Register<Obj> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = IterMut<'a, Obj>;
    fn into_iter(self) -> Self::IntoIter { self.iter_mut() }
}

impl<'a, Str, Obj: ?Sized> Index<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{
    type Output = Obj;
    fn index(&self, name: &'a Str) -> &Self::Output {
        self.get_object(name.borrow()).unwrap()
    }
}

impl<'a, Str, Obj: ?Sized> IndexMut<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{
    fn index_mut(&mut self, name: &'a Str) -> &mut Self::Output {
        self.get_object_mut(name.borrow()).unwrap()
    }
}

unsafe impl<'a, Str, Obj: ?Sized> MultiIndexable<&'a Str> for Register<Obj>
    where Str: Ord + Borrow<str>, Obj: Any
{}

// ++++++++++++++++++++ RegisterModifier ++++++++++++++++++++

pub struct RegisterModifier<Obj: Any + ?Sized = DefaultBase>(Register<Obj>);

impl<Obj: Any + ?Sized> Deref for RegisterModifier<Obj> {
    type Target = Register<Obj>;
    fn deref(&self) -> &Self::Target { &self.0 }
}
impl<Obj: Any + ?Sized> DerefMut for RegisterModifier<Obj> {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

// TODO: remove duplicated code
impl<Obj: Any + ?Sized> RegisterModifier<Obj> {
    pub fn new() -> RegisterModifier<Obj> {
        RegisterModifier(Register{ entrys: BTreeMap::new() })
    }

    pub fn unwrap(self) -> Register<Obj> { self.0 }

    pub fn add_single(&mut self, name: String, obj: Box<Obj>){
        assert!(self.entrys.contains_key(&name), "Option '{}' already exists!", &name);

        self.entrys.insert(name, Entry::Single(obj));
    }

    pub fn add_option(&mut self, name: String){
        assert!(self.entrys.contains_key(&name), "Option '{}' already exists!", &name);

        self.entrys.insert(name, Entry::Multi{
            wired: None, alternatives: Vec::new()
        });
    }

    pub fn add_alternative(&mut self, opt_name: &str, alt_name: String, obj: Box<Obj>){
        let entry = self.entrys.get_mut(opt_name);
        let entry = entry.expect(&format!("Option '{}' doesn't exist", &opt_name));

        entry.add_alternative(alt_name, obj);
    }

    pub fn wire_alternative(&mut self, opt_name: &str, alt_name: &str){
        let entry = self.entrys.get_mut(opt_name);
        let entry = entry.expect(&format!("Option '{}' doesn't exist", &opt_name));

        entry.wire_alternative(alt_name);
    }
}

<|endoftext|>


<commit_before>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;
use std::collections::BTreeMap;
use std::fmt::Debug;

pub trait NodeType: Clone + Debug + Send + Sized {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

pub trait LinkWeight: Clone + Debug + Send + Sized {
}

impl LinkWeight for f64 {}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
pub struct Link<L: LinkWeight> {
    pub node_idx: NodeIndex,
    pub weight: L,
}

#[derive(Clone, Debug)]
pub struct Node<N: NodeType, L: LinkWeight> {
    pub node_type: N,
    pub forward_links: Vec<Link<L>>,
}

struct CycleDetector<'a, N: NodeType + 'a, L: LinkWeight + 'a> {
    nodes: &'a [Node<N, L>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, N: NodeType + 'a, L: LinkWeight + 'a> CycleDetector<'a, N, L> {
    fn new(network: &'a Network<N, L>) -> CycleDetector<'a, N, L> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn link_would_cycle(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        let path_from = target_node_idx.index();
        let path_to = source_node_idx.index();

        assert!(path_from != path_to);

        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from the target_node and iterate all paths from there. If we hit the source node,
        // the addition of this link would lead towards a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].forward_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

#[derive(Clone, Debug)]
/// A directed, acylic network.
pub struct Network<N: NodeType, L: LinkWeight> {
    nodes: Vec<Node<N, L>>,
}

impl<N: NodeType, L: LinkWeight> Network<N, L> {
    pub fn new() -> Network<N, L> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<N, L>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            forward_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.forward_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix; // make immutable

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order; // make immutable

        let mut cycler = CycleDetector::new(self);
        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !cycler.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).link_would_cycle(source_node_idx, target_node_idx)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: L) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].forward_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });
    }
}

#[derive(Clone, Debug)]
pub struct NetworkMap<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> {
    network: Network<N, L>,
    node_map: BTreeMap<NKEY, NodeIndex>,
    node_map_rev: BTreeMap<NodeIndex, NKEY>,
}

impl<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> NetworkMap<NKEY, N, L> {
    pub fn new() -> NetworkMap<NKEY, N, L> {
        NetworkMap {
            network: Network::new(),
            node_map: BTreeMap::new(),
            node_map_rev: BTreeMap::new(),
        }
    }

    pub fn network(&self) -> &Network<N, L> {
        &self.network
    }

    pub fn nodes(&self) -> &[Node<N, L>] {
        self.network.nodes()
    }

    /// Registers/creates a new node under the external key `node_key`.
    ///
    /// # Panics
    ///
    /// If a node with `node_key` already exists.
    pub fn add_node(&mut self, node_key: NKEY, node_type: N) {
        // XXX: Use node_map.entry()
        if self.node_map.contains_key(&node_key) {
            panic!("Duplicate node index");
        }
        let idx = self.network.add_node(node_type);
        self.node_map.insert(node_key.clone(), idx);
        self.node_map_rev.insert(idx, node_key);
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(&NKEY, &NKEY)> {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((a, b)) => Some((&self.node_map_rev[&a], &self.node_map_rev[&b])),
            None => None,
        }
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_key: NKEY, target_node_key: NKEY) -> bool {
        self.network.link_would_cycle(self.node_map[&source_node_key],
                                      self.node_map[&target_node_key])
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_key: NKEY,
                      target_node_key: NKEY)
                      -> Result<(), &'static str> {
        self.network.valid_link(self.node_map[&source_node_key],
                                self.node_map[&target_node_key])
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_key: NKEY, target_node_key: NKEY, weight: L) {
        self.network.add_link(self.node_map[&source_node_key],
                              self.node_map[&target_node_key],
                              weight)
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    #[derive(Clone, Debug)]
    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let h1 = g.add_node(NodeT::Hidden);
        let h2 = g.add_node(NodeT::Hidden);
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let o1 = g.add_node(NodeT::Output);
        let o2 = g.add_node(NodeT::Output);

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<commit_msg>Make fields of Node private. Make Link private. Instead provide accessor methods.<commit_after>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;
use std::collections::BTreeMap;
use std::fmt::Debug;

pub trait NodeType: Clone + Debug + Send + Sized {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

pub trait LinkWeight: Clone + Copy + Debug + Send + Sized {
}

impl LinkWeight for f64 {}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    #[inline(always)]
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    #[inline(always)]
    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
struct Link<L: LinkWeight> {
    node_idx: NodeIndex,
    weight: L,
}

#[derive(Clone, Debug)]
pub struct Node<N: NodeType, L: LinkWeight> {
    node_type: N,
    forward_links: Vec<Link<L>>,
}

impl<N: NodeType, L: LinkWeight> Node<N, L> {
    #[inline(always)]
    pub fn node_type(&self) -> &N {
        &self.node_type
    }

    pub fn each_active_forward_link<F>(&self, mut f: F)
        where F: FnMut(NodeIndex, L)
    {
        for link in &self.forward_links {
            // XXX: if link is active and not deleted
            f(link.node_idx, link.weight);
        }
    }
}

struct CycleDetector<'a, N: NodeType + 'a, L: LinkWeight + 'a> {
    nodes: &'a [Node<N, L>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, N: NodeType + 'a, L: LinkWeight + 'a> CycleDetector<'a, N, L> {
    fn new(network: &'a Network<N, L>) -> CycleDetector<'a, N, L> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn link_would_cycle(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        let path_from = target_node_idx.index();
        let path_to = source_node_idx.index();

        assert!(path_from != path_to);

        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from the target_node and iterate all paths from there. If we hit the source node,
        // the addition of this link would lead towards a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].forward_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

#[derive(Clone, Debug)]
/// A directed, acylic network.
pub struct Network<N: NodeType, L: LinkWeight> {
    nodes: Vec<Node<N, L>>,
}

impl<N: NodeType, L: LinkWeight> Network<N, L> {
    pub fn new() -> Network<N, L> {
        Network { nodes: Vec::new() }
    }

    #[inline(always)]
    pub fn nodes(&self) -> &[Node<N, L>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            forward_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.forward_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix; // make immutable

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order; // make immutable

        let mut cycler = CycleDetector::new(self);
        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !cycler.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).link_would_cycle(source_node_idx, target_node_idx)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: L) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].forward_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });
    }
}

#[derive(Clone, Debug)]
pub struct NetworkMap<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> {
    network: Network<N, L>,
    node_map: BTreeMap<NKEY, NodeIndex>,
    node_map_rev: BTreeMap<NodeIndex, NKEY>,
}

impl<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> NetworkMap<NKEY, N, L> {
    pub fn new() -> NetworkMap<NKEY, N, L> {
        NetworkMap {
            network: Network::new(),
            node_map: BTreeMap::new(),
            node_map_rev: BTreeMap::new(),
        }
    }

    pub fn network(&self) -> &Network<N, L> {
        &self.network
    }

    pub fn nodes(&self) -> &[Node<N, L>] {
        self.network.nodes()
    }

    /// Registers/creates a new node under the external key `node_key`.
    ///
    /// # Panics
    ///
    /// If a node with `node_key` already exists.
    pub fn add_node(&mut self, node_key: NKEY, node_type: N) {
        // XXX: Use node_map.entry()
        if self.node_map.contains_key(&node_key) {
            panic!("Duplicate node index");
        }
        let idx = self.network.add_node(node_type);
        self.node_map.insert(node_key.clone(), idx);
        self.node_map_rev.insert(idx, node_key);
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(&NKEY, &NKEY)> {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((a, b)) => Some((&self.node_map_rev[&a], &self.node_map_rev[&b])),
            None => None,
        }
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_key: NKEY, target_node_key: NKEY) -> bool {
        self.network.link_would_cycle(self.node_map[&source_node_key],
                                      self.node_map[&target_node_key])
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_key: NKEY,
                      target_node_key: NKEY)
                      -> Result<(), &'static str> {
        self.network.valid_link(self.node_map[&source_node_key],
                                self.node_map[&target_node_key])
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_key: NKEY, target_node_key: NKEY, weight: L) {
        self.network.add_link(self.node_map[&source_node_key],
                              self.node_map[&target_node_key],
                              weight)
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    #[derive(Clone, Debug)]
    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let h1 = g.add_node(NodeT::Hidden);
        let h2 = g.add_node(NodeT::Hidden);
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let o1 = g.add_node(NodeT::Output);
        let o2 = g.add_node(NodeT::Output);

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Nikita Pekin and the xkcd_rs contributors
// See the README.md file at the top-level directory of this distribution.
//
// 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.

#![deny(missing_docs)]
#![deny(non_camel_case_types)]
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

//! A library providing Rust bindings for the XKCD web API.
//!
//! The library provides a `XkcdRequestSender` trait which can be implemented by
//! various request senders. These implementations may then be used to execute
//! requests to the API.
//!
//! If the `hyper` feature is enabled during compilation, then this library
//! provides an implementation of the `XkcdRequestSender` trait for the
//! `hyper::Client` of the [`hyper`](https://github.com/hyperium/hyper) library.
//!
//! Response bodies are deserialized from JSON into structs via the
//! [`serde_json`](https://github.com/serde-rs/json) library.

#[cfg(feature = "hyper")]
extern crate hyper;

#[macro_use]
extern crate log;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate url;
extern crate url_serde;

mod error;

pub use self::error::{Error, HttpRequestError, HttpRequestResult, Result};
pub use self::model::XkcdResponse;

pub mod comics;
pub mod model;
pub mod random;

use std::fmt::Debug;

use serde::Deserialize;

fn parse_xkcd_response<T>(response: &str) -> Result<T>
    where T: Debug + Deserialize,
{
    let parsed_response = serde_json::from_str(response)?;
    trace!("Parsed response: {:?}", parsed_response);
    Ok(parsed_response)
}

/// Functionality for sending requests to the XKCD API via HTTPS.
///
/// Should be implemented for clients to send requests to the XKCD API.
pub trait XkcdRequestSender {
    /// Performs an API call to the XKCD web API.
    fn send(&self, method: &str) -> HttpRequestResult<String>;
}

#[cfg(feature = "hyper")]
mod hyper_support {
    use std::io::Read;

    use hyper;
    use hyper::status::StatusCode;
    use url::Url;

    use error::{HttpRequestError, HttpRequestResult};

    use super::XkcdRequestSender;

    impl XkcdRequestSender for hyper::Client {
        fn send<'a>(&self, method: &str) -> HttpRequestResult<String> {
            let url_string = format!("https://xkcd.com/{}", method);
            let url = url_string.parse::<Url>().expect("Unable to parse URL");

            trace!("Sending query to url: {}", url);
            let mut response = self.get(url.clone()).send()?;

            trace!("Status code: {}", response.status);
            // Ensure we got a valid status code.
            match response.status {
                StatusCode::NotFound => return Err(HttpRequestError::not_found(url)),
                _ => {}
            }

            let mut result = String::new();
            response.read_to_string(&mut result)?;
            trace!("Query result: {}", result);

            Ok(result)
        }
    }

    impl From<hyper::Error> for HttpRequestError {
        fn from(error: hyper::Error) -> HttpRequestError {
            match error {
                hyper::Error::Io(e) => HttpRequestError::Io(e),
                e => HttpRequestError::Other(Box::new(e)),
            }
        }
    }
}

#[cfg(feature = "hyper")]
pub use hyper_support::*;

#[cfg(test)]
mod test_helpers {
    use super::{XkcdRequestSender, HttpRequestError};

    pub struct MockXkcdRequestSender {
        response: String,
    }

    impl MockXkcdRequestSender {
        pub fn respond_with<S: Into<String>>(response: S) -> Self {
            MockXkcdRequestSender { response: response.into() }
        }
    }

    impl XkcdRequestSender for MockXkcdRequestSender {
        fn send(&self, _: &str) -> Result<String, HttpRequestError> {
            Ok(self.response.clone())
        }
    }
}

#[cfg(test)]
mod tests {
    use url::Url;

    use model::XkcdResponse;

    use super::parse_xkcd_response;

    #[test]
    fn test_parse_xkcd_response() {
        let result = r#"
            {
                "month": "6",
                "num": 1698,
                "link": "",
                "year": "2016",
                "news": "",
                "safe_title": "Theft Quadrants",
                "transcript": "",
                "alt": "TinyURL was the most popular link shortener for long enough that it made it into a lot of printed publications. I wonder what year the domain will finally lapse and get picked up by a porn site.",
                "img": "http:\/\/imgs.xkcd.com\/comics\/theft_quadrants.png",
                "title": "Theft Quadrants",
                "day": "24"
            }
        "#;
        let response = parse_xkcd_response::<XkcdResponse>(&result).unwrap();
        assert_eq!(response,
                   XkcdResponse {
                       month: 6,
                       num: 1698,
                       link: "".to_owned(),
                       year: 2016,
                       news: "".to_owned(),
                       safe_title: "Theft Quadrants".to_owned(),
                       transcript: "".to_owned(),
                       alt: "TinyURL was the most popular link shortener for long enough that it \
                             made it into a lot of printed publications. I wonder what year the \
                             domain will finally lapse and get picked up by a porn site."
                           .to_owned(),
                       img: "http://imgs.xkcd.com/comics/theft_quadrants.png"
                           .to_owned()
                           .parse::<Url>()
                           .unwrap(),
                       title: "Theft Quadrants".to_owned(),
                       day: 24,
                   });
    }
}
<commit_msg>chore: remove unused lifetime<commit_after>// Copyright (c) 2016 Nikita Pekin and the xkcd_rs contributors
// See the README.md file at the top-level directory of this distribution.
//
// 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.

#![deny(missing_docs)]
#![deny(non_camel_case_types)]
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

//! A library providing Rust bindings for the XKCD web API.
//!
//! The library provides a `XkcdRequestSender` trait which can be implemented by
//! various request senders. These implementations may then be used to execute
//! requests to the API.
//!
//! If the `hyper` feature is enabled during compilation, then this library
//! provides an implementation of the `XkcdRequestSender` trait for the
//! `hyper::Client` of the [`hyper`](https://github.com/hyperium/hyper) library.
//!
//! Response bodies are deserialized from JSON into structs via the
//! [`serde_json`](https://github.com/serde-rs/json) library.

#[cfg(feature = "hyper")]
extern crate hyper;

#[macro_use]
extern crate log;
extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate url;
extern crate url_serde;

mod error;

pub use self::error::{Error, HttpRequestError, HttpRequestResult, Result};
pub use self::model::XkcdResponse;

pub mod comics;
pub mod model;
pub mod random;

use std::fmt::Debug;

use serde::Deserialize;

fn parse_xkcd_response<T>(response: &str) -> Result<T>
    where T: Debug + Deserialize,
{
    let parsed_response = serde_json::from_str(response)?;
    trace!("Parsed response: {:?}", parsed_response);
    Ok(parsed_response)
}

/// Functionality for sending requests to the XKCD API via HTTPS.
///
/// Should be implemented for clients to send requests to the XKCD API.
pub trait XkcdRequestSender {
    /// Performs an API call to the XKCD web API.
    fn send(&self, method: &str) -> HttpRequestResult<String>;
}

#[cfg(feature = "hyper")]
mod hyper_support {
    use std::io::Read;

    use hyper;
    use hyper::status::StatusCode;
    use url::Url;

    use error::{HttpRequestError, HttpRequestResult};

    use super::XkcdRequestSender;

    impl XkcdRequestSender for hyper::Client {
        fn send(&self, method: &str) -> HttpRequestResult<String> {
            let url_string = format!("https://xkcd.com/{}", method);
            let url = url_string.parse::<Url>().expect("Unable to parse URL");

            trace!("Sending query to url: {}", url);
            let mut response = self.get(url.clone()).send()?;

            trace!("Status code: {}", response.status);
            // Ensure we got a valid status code.
            match response.status {
                StatusCode::NotFound => return Err(HttpRequestError::not_found(url)),
                _ => {}
            }

            let mut result = String::new();
            response.read_to_string(&mut result)?;
            trace!("Query result: {}", result);

            Ok(result)
        }
    }

    impl From<hyper::Error> for HttpRequestError {
        fn from(error: hyper::Error) -> HttpRequestError {
            match error {
                hyper::Error::Io(e) => HttpRequestError::Io(e),
                e => HttpRequestError::Other(Box::new(e)),
            }
        }
    }
}

#[cfg(feature = "hyper")]
pub use hyper_support::*;

#[cfg(test)]
mod test_helpers {
    use super::{XkcdRequestSender, HttpRequestError};

    pub struct MockXkcdRequestSender {
        response: String,
    }

    impl MockXkcdRequestSender {
        pub fn respond_with<S: Into<String>>(response: S) -> Self {
            MockXkcdRequestSender { response: response.into() }
        }
    }

    impl XkcdRequestSender for MockXkcdRequestSender {
        fn send(&self, _: &str) -> Result<String, HttpRequestError> {
            Ok(self.response.clone())
        }
    }
}

#[cfg(test)]
mod tests {
    use url::Url;

    use model::XkcdResponse;

    use super::parse_xkcd_response;

    #[test]
    fn test_parse_xkcd_response() {
        let result = r#"
            {
                "month": "6",
                "num": 1698,
                "link": "",
                "year": "2016",
                "news": "",
                "safe_title": "Theft Quadrants",
                "transcript": "",
                "alt": "TinyURL was the most popular link shortener for long enough that it made it into a lot of printed publications. I wonder what year the domain will finally lapse and get picked up by a porn site.",
                "img": "http:\/\/imgs.xkcd.com\/comics\/theft_quadrants.png",
                "title": "Theft Quadrants",
                "day": "24"
            }
        "#;
        let response = parse_xkcd_response::<XkcdResponse>(&result).unwrap();
        assert_eq!(response,
                   XkcdResponse {
                       month: 6,
                       num: 1698,
                       link: "".to_owned(),
                       year: 2016,
                       news: "".to_owned(),
                       safe_title: "Theft Quadrants".to_owned(),
                       transcript: "".to_owned(),
                       alt: "TinyURL was the most popular link shortener for long enough that it \
                             made it into a lot of printed publications. I wonder what year the \
                             domain will finally lapse and get picked up by a porn site."
                           .to_owned(),
                       img: "http://imgs.xkcd.com/comics/theft_quadrants.png"
                           .to_owned()
                           .parse::<Url>()
                           .unwrap(),
                       title: "Theft Quadrants".to_owned(),
                       day: 24,
                   });
    }
}
<|endoftext|>


<commit_before>//! A simple garbage collector for use in Rust.
//!
//! The goal is to help you quickly build a VM in Rust.
//! So this GC is designed for:
//!
//! *   Safety
//!
//! *   No dependency on linters or compiler plugins
//!
//! *   An API that's consistent with a high-performance implementation
//!     (though right now cell-gc is not speedy)
//!
//! *   Fun
//!
//!
//! # Caveats
//!
//! **cell-gc only works for toy-sized programs at present.**
//! [See issue #4.](https://github.com/jorendorff/rust-toy-gc/issues/4)
//!
//! **cell-gc is for use in VMs.** So the assumption is that the data the GC is
//! managing is not really *your* data; it's your end user's data. If you don't
//! want every field of every GC-managed object to be public and mutable, cell-gc
//! is not the GC for your project!
//!
//! **The API is completely unstable.** I promise I will change it in ways
//! that will break code; you'll just have to keep up until things stabilize.
//!
//! cell-gc is not designed to support multithread access to a single heap (like Java).
//! Instead, you can create one heap per thread (like JavaScript).
//!
//! Currently it does not support lots of small heaps with random lifetimes (like Erlang),
//! but I have some ideas on how to get there.
//!
//!
//! # How to use it
//!
//! There are two parts to using `cell_gc`: GC types and GC heaps.
//!
//! ## Declaring GC types
//!
//! Declaring GC types is actually super easy. Just add `#[derive(IntoHeap)]`
//! to any struct:
//!
//! ```rust
//! #[macro_use] extern crate cell_gc;
//! #[macro_use] extern crate cell_gc_derive;
//!
//! /// A linked list of numbers that lives in the GC heap.
//! /// The `#[derive(IntoHeap)]` here causes Rust to define an additional
//! /// type, `IntListRef`.
//! #[derive(IntoHeap)]
//! struct IntList<'h> {
//!     head: i64,
//!     tail: Option<IntListRef<'h>>
//! }
//! # fn main(){}
//! ```
//!
//! `cell_gc` does several things:
//!
//! *   Behind the scenes, it generates some code used for garbage collection,
//!     such as marking code. You never need to worry about that stuff.
//!
//! *   It checks that `IntList`'s fields are all GC-safe.
//!
//!     Not every type is safe to use as a field of a heap struct or enum.
//!     Here are the allowed field types:
//!
//!     * primitive types, like `i32`
//!     * types declared with `#[derive(IntoHeap)]`, like `IntList<'h>` and `IntListRef<'h>`
//!     * `Box<T>` where `T` has `'static` lifetime
//!     * `Rc<T>` where `T` has `'static` lifetime
//!     * `Option<T>` where `T` is any of these types
//!
//!     If you try to use anything else, you'll get bizarre error messages
//!     from `rustc`.
//!
//! *   It declare a `Ref` type for you, in this case `IntListRef`.
//!     `cell_gc` names this type by gluing `Ref` to the end of the struct
//!     name. `IntListRef` is a smart pointer to a GC-managed `IntList`. You
//!     need this because `cell_gc` doesn't let you have normal Rust references
//!     to stuff in the GC heap.
//!
//!     `IntListRef` values keep in-heap `IntList` values alive; once the last
//!     `IntListRef` pointing at an object is gone, it becomes available for
//!     garbage collection, and eventually it'll be recycled.
//!
//!     `IntListRef` is like `std::rc::Rc`: it's `Clone` but not `Copy`, and
//!     calling `.clone()` copies the Ref, not the object it points to.
//!
//!     `Ref` types have accessor methods for getting and setting each
//!     field of the struct. For example, `IntList` has methods `.head()`, `.tail()`,
//!     `.set_head(i64)`, and `.set_tail(Option<IntListRef>)`.
//!
//! You can also derive `IntoHeap` for an enum, but support is incomplete: no
//! `Ref` type is generated for enums. Tuple structs are not supported.
//!
//! ## Understanding heaps
//!
//! This part isn't documented well yet. But here's an example,
//! using the `IntList` from above:
//!
//! ```rust
//! # #[macro_use] extern crate cell_gc;
//! # #[macro_use] extern crate cell_gc_derive;
//! # #[derive(IntoHeap)]
//! # struct IntList<'h> {
//! #     head: i64,
//! #     tail: Option<IntListRef<'h>>
//! # }
//! fn main() {
//!     // Create a heap (you'll only do this once in your whole program)
//!     cell_gc::with_heap(|heap| {
//!         // Allocate an object (returns an IntListRef)
//!         let obj1 = heap.alloc(IntList { head: 17, tail: None });
//!         assert_eq!(obj1.head(), 17);
//!         assert_eq!(obj1.tail(), None);
//!
//!         // Allocate another object
//!         let obj2 = heap.alloc(IntList { head: 33, tail: Some(obj1) });
//!         assert_eq!(obj2.head(), 33);
//!         assert_eq!(obj2.tail().unwrap().head(), 17);
//!     });
//! }
//! ```
//!
//! Use `with_heap` in your `main()` function to create a heap.
//! Use `heap.alloc(v)` to allocate values in the heap.
//!
//! # Vectors in the GC heap
//!
//! A very simple "object" type for a text adventure game:
//!
//! ```rust
//! #[macro_use] extern crate cell_gc;
//! #[macro_use] extern crate cell_gc_derive;
//!
//! use cell_gc::collections::VecRef;
//!
//! #[derive(IntoHeap)]
//! struct Object<'h> {
//!     name: String,
//!     description: String,
//!     children: VecRef<'h, ObjectRef<'h>>
//! }
//! # fn main() {}
//! ```
//!
//! Note that `children` is a `VecRef<'h, ObjectRef<'h>>`; that is, it is
//! a reference to a separately GC-allocated `Vec<ObjectRef<'h>>`, which is
//! a vector of references to other objects. In other words, this is exactly
//! what you would have in Java for a field declared like this:
//!
//! ```java
//! public ArrayList<Object> children;
//! ```
//!
//! The API generated by this macro looks like this:
//!
//! ```rust
//! # struct VecRef<'h, T: 'h>(&'h T);  // hack to make this compile
//! struct Object<'h> {
//!     name: String,
//!     description: String,
//!     children: VecRef<'h, ObjectRef<'h>>
//! }
//!
//! struct ObjectRef<'h> {
//!    /* all fields private */
//! #  target: &'h Object<'h>     // hack to make this compile
//! }
//!
//! impl<'h> ObjectRef<'h> {
//!     fn name(&self) -> String
//! #       { unimplemented!(); }
//!     fn set_name(&self, name: String)
//! #       { unimplemented!(); }
//!     fn description(&self) -> String
//! #       { unimplemented!(); }
//!     fn set_description(&self, description: String)
//! #       { unimplemented!(); }
//!     fn children(&self) -> VecRef<'h, ObjectRef<'h>>
//! #       { unimplemented!(); }
//!     fn set_children(&self, children: VecRef<'h, ObjectRef<'h>>)
//! #       { unimplemented!(); }
//! }
//! ```
//!
//! (You might never actually use that `set_children()` method.
//! Instead, you'll initialize the `children` field with a vector when you
//! create the object, and then you'll most likely mutate that existing vector
//! rather than ever creating a new one.)
//!
//! You can allocate `Object`s in the heap using `heap.alloc(Object { ... })`,
//! and make one `Object` a child of another by using `obj1.children().push(obj2)`.
//!
//! # Safety
//!
//! As long as you don't type the keyword `unsafe` in your code,
//! this GC is safe.[citation needed]
//!
//! Still, there's one weird rule to be aware of:
//! **Don't implement `Drop` or `Clone`
//! for any type declared using `gc_heap_type!`.**
//! It's safe in the full Rust sense of that word
//! (it won't cause crashes or undefined behavior,
//! as long as your `.drop()` or `.clone()` method does nothing `unsafe`),
//! but it won't do what you want.
//! Your `.drop()` and `.clone()` methods simply will not be called when you expect;
//! and they'll be called at other times that make no sense.
//!
//! So don't do that!
//! The safe alternative is to put a `Box` or `Rc` around your value
//! (the one that implements `Drop` or `Clone`)
//! and use that as a field of a GC heap struct.
//!
//!
//! # Why is it called "cell-gc"?
//!
//! In cell-gc, every field of every GC-managed object is mutable.
//! You can't get *direct* references to the data;
//! instead you use methods to get and set values.
//!
//! It's as though every field were a [Cell](http://doc.rust-lang.org/std/cell/struct.Cell.html).

extern crate bit_vec;

pub mod traits;
mod pages;
mod heap;
mod gcref;
mod gcleaf;
pub mod collections;

pub use heap::{Heap, HeapSession, with_heap};
pub use gcref::GCRef;
pub use gcleaf::GCLeaf;

/// Return the number of allocations of a given type that fit in a "page".
/// (Unstable. This is a temporary hack for testing.)
pub fn page_capacity<'h, T: traits::IntoHeapAllocation<'h>>() -> usize {
    pages::TypedPage::<T::In>::capacity()
}
<commit_msg>Update documentation for owned heaps.<commit_after>//! A simple garbage collector for use in Rust.
//!
//! The goal is to help you quickly build a VM in Rust.
//! So this GC is designed for:
//!
//! *   Safety
//!
//! *   No dependency on linters or compiler plugins
//!
//! *   An API that's consistent with a high-performance implementation
//!     (though right now cell-gc is not speedy)
//!
//! *   Fun
//!
//!
//! # Caveats
//!
//! **cell-gc only works for toy-sized programs at present.**
//! [See issue #4.](https://github.com/jorendorff/rust-toy-gc/issues/4)
//!
//! **cell-gc is for use in VMs.** So the assumption is that the data the GC is
//! managing is not really *your* data; it's your end user's data. If you don't
//! want every field of every GC-managed object to be public and mutable, cell-gc
//! is not the GC for your project!
//!
//! **The API is completely unstable.** I promise I will change it in ways
//! that will break code; you'll just have to keep up until things stabilize.
//!
//! cell-gc is not designed to support multithread access to a single heap (like Java).
//! Instead, you can create one heap per thread (like JavaScript).
//!
//! Currently it does not support lots of small heaps with random lifetimes (like Erlang),
//! but I have some ideas on how to get there.
//!
//!
//! # How to use it
//!
//! There are two parts to using `cell_gc`: GC types and GC heaps.
//!
//! ## Declaring GC types
//!
//! Declaring GC types is actually super easy. Just add `#[derive(IntoHeap)]`
//! to any struct:
//!
//! ```rust
//! #[macro_use] extern crate cell_gc;
//! #[macro_use] extern crate cell_gc_derive;
//!
//! /// A linked list of numbers that lives in the GC heap.
//! /// The `#[derive(IntoHeap)]` here causes Rust to define an additional
//! /// type, `IntListRef`.
//! #[derive(IntoHeap)]
//! struct IntList<'h> {
//!     head: i64,
//!     tail: Option<IntListRef<'h>>
//! }
//! # fn main(){}
//! ```
//!
//! `cell_gc` does several things:
//!
//! *   Behind the scenes, it generates some code used for garbage collection,
//!     such as marking code. You never need to worry about that stuff.
//!
//! *   It checks that `IntList`'s fields are all GC-safe.
//!
//!     Not every type is safe to use as a field of a heap struct or enum.
//!     Here are the allowed field types:
//!
//!     * primitive types, like `i32`
//!     * types declared with `#[derive(IntoHeap)]`, like `IntList<'h>` and `IntListRef<'h>`
//!     * `Box<T>` where `T` has `'static` lifetime
//!     * `Rc<T>` where `T` has `'static` lifetime
//!     * `Option<T>` where `T` is any of these types
//!
//!     If you try to use anything else, you'll get bizarre error messages
//!     from `rustc`.
//!
//! *   It declare a `Ref` type for you, in this case `IntListRef`.
//!     `cell_gc` names this type by gluing `Ref` to the end of the struct
//!     name. `IntListRef` is a smart pointer to a GC-managed `IntList`. You
//!     need this because `cell_gc` doesn't let you have normal Rust references
//!     to stuff in the GC heap.
//!
//!     `IntListRef` values keep in-heap `IntList` values alive; once the last
//!     `IntListRef` pointing at an object is gone, it becomes available for
//!     garbage collection, and eventually it'll be recycled.
//!
//!     `IntListRef` is like `std::rc::Rc`: it's `Clone` but not `Copy`, and
//!     calling `.clone()` copies the Ref, not the object it points to.
//!
//!     `Ref` types have accessor methods for getting and setting each
//!     field of the struct. For example, `IntList` has methods `.head()`, `.tail()`,
//!     `.set_head(i64)`, and `.set_tail(Option<IntListRef>)`.
//!
//! You can also derive `IntoHeap` for an enum, but support is incomplete: no
//! `Ref` type is generated for enums. Tuple structs are not supported.
//!
//! ## Understanding heaps
//!
//! This part isn't documented well yet. But here's an example,
//! using the `IntList` from above:
//!
//! ```rust
//! # #[macro_use] extern crate cell_gc;
//! # #[macro_use] extern crate cell_gc_derive;
//! # #[derive(IntoHeap)]
//! # struct IntList<'h> {
//! #     head: i64,
//! #     tail: Option<IntListRef<'h>>
//! # }
//! use cell_gc::Heap;
//!
//! fn main() {
//!     // Create a heap (you'll only do this once in your whole program)
//!     let mut heap = Heap::new();
//!
//!     heap.enter(|hs| {
//!         // Allocate an object (returns an IntListRef)
//!         let obj1 = hs.alloc(IntList { head: 17, tail: None });
//!         assert_eq!(obj1.head(), 17);
//!         assert_eq!(obj1.tail(), None);
//!
//!         // Allocate another object
//!         let obj2 = hs.alloc(IntList { head: 33, tail: Some(obj1) });
//!         assert_eq!(obj2.head(), 33);
//!         assert_eq!(obj2.tail().unwrap().head(), 17);
//!     });
//! }
//! ```
//!
//! Use `Heap::new()` in your `main()` function to create a heap.
//! Use `heap.enter()` to gain access to the heap (opening a "heap session", `hs`).
//! Use `hs.alloc(v)` to allocate values in the heap.
//!
//! # Vectors in the GC heap
//!
//! A very simple "object" type for a text adventure game:
//!
//! ```rust
//! #[macro_use] extern crate cell_gc;
//! #[macro_use] extern crate cell_gc_derive;
//!
//! use cell_gc::collections::VecRef;
//!
//! #[derive(IntoHeap)]
//! struct Object<'h> {
//!     name: String,
//!     description: String,
//!     children: VecRef<'h, ObjectRef<'h>>
//! }
//! # fn main() {}
//! ```
//!
//! Note that `children` is a `VecRef<'h, ObjectRef<'h>>`; that is, it is
//! a reference to a separately GC-allocated `Vec<ObjectRef<'h>>`, which is
//! a vector of references to other objects. In other words, this is exactly
//! what you would have in Java for a field declared like this:
//!
//! ```java
//! public ArrayList<Object> children;
//! ```
//!
//! The API generated by this macro looks like this:
//!
//! ```rust
//! # struct VecRef<'h, T: 'h>(&'h T);  // hack to make this compile
//! struct Object<'h> {
//!     name: String,
//!     description: String,
//!     children: VecRef<'h, ObjectRef<'h>>
//! }
//!
//! struct ObjectRef<'h> {
//!    /* all fields private */
//! #  target: &'h Object<'h>     // hack to make this compile
//! }
//!
//! impl<'h> ObjectRef<'h> {
//!     fn name(&self) -> String
//! #       { unimplemented!(); }
//!     fn set_name(&self, name: String)
//! #       { unimplemented!(); }
//!     fn description(&self) -> String
//! #       { unimplemented!(); }
//!     fn set_description(&self, description: String)
//! #       { unimplemented!(); }
//!     fn children(&self) -> VecRef<'h, ObjectRef<'h>>
//! #       { unimplemented!(); }
//!     fn set_children(&self, children: VecRef<'h, ObjectRef<'h>>)
//! #       { unimplemented!(); }
//! }
//! ```
//!
//! (You might never actually use that `set_children()` method.
//! Instead, you'll initialize the `children` field with a vector when you
//! create the object, and then you'll most likely mutate that existing vector
//! rather than ever creating a new one.)
//!
//! You can allocate `Object`s in the heap using `hs.alloc(Object { ... })`,
//! and make one `Object` a child of another by using `obj1.children().push(obj2)`.
//!
//! # Safety
//!
//! As long as you don't type the keyword `unsafe` in your code,
//! this GC is safe.[citation needed]
//!
//! Still, there's one weird rule to be aware of:
//! **Don't implement `Drop` or `Clone`
//! for any type declared using `derive(IntoHeap)`.**
//! It's safe in the full Rust sense of that word
//! (it won't cause crashes or undefined behavior,
//! as long as your `.drop()` or `.clone()` method does nothing `unsafe`),
//! but it won't do what you want.
//! Your `.drop()` and `.clone()` methods simply will not be called when you expect;
//! and they'll be called at other times that make no sense.
//!
//! So don't do that!
//! The safe alternative is to put a `Box` or `Rc` around your value
//! (the one that implements `Drop` or `Clone`)
//! and use that as a field of a GC heap struct.
//!
//!
//! # Why is it called "cell-gc"?
//!
//! In cell-gc, every field of every GC-managed object is mutable.
//! You can't get *direct* references to the data;
//! instead you use methods to get and set values.
//!
//! It's as though every field were a [Cell](http://doc.rust-lang.org/std/cell/struct.Cell.html).

extern crate bit_vec;

pub mod traits;
mod pages;
mod heap;
mod gcref;
mod gcleaf;
pub mod collections;

pub use heap::{Heap, HeapSession, with_heap};
pub use gcref::GCRef;
pub use gcleaf::GCLeaf;

/// Return the number of allocations of a given type that fit in a "page".
/// (Unstable. This is a temporary hack for testing.)
pub fn page_capacity<'h, T: traits::IntoHeapAllocation<'h>>() -> usize {
    pages::TypedPage::<T::In>::capacity()
}
<|endoftext|>