diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index d28504db585c7..a656cb3126de7 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -66,7 +66,7 @@ pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. - predicates: ObligationForest>, + predicates: ObligationForest, ()>, // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must @@ -192,7 +192,7 @@ impl<'tcx> FulfillmentContext<'tcx> { obligation: obligation, stalled_on: vec![] }; - self.predicates.push_root(obligation); + self.predicates.push_tree(obligation, ()); } pub fn region_obligations(&self, @@ -278,10 +278,10 @@ impl<'tcx> FulfillmentContext<'tcx> { let outcome = { let region_obligations = &mut self.region_obligations; self.predicates.process_obligations( - |obligation, backtrace| process_predicate(selcx, - obligation, - backtrace, - region_obligations)) + |obligation, _tree, backtrace| process_predicate(selcx, + obligation, + backtrace, + region_obligations)) }; debug!("select_where_possible: outcome={:?}", outcome); @@ -405,7 +405,7 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, pending_obligation.stalled_on = vec![]; } - let obligation = &pending_obligation.obligation; + let obligation = &mut pending_obligation.obligation; // If we exceed the recursion limit, take a moment to look for a // cycle so we can give a better error report from here, where we @@ -417,8 +417,16 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } + if obligation.predicate.has_infer_types() { + obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); + } + match obligation.predicate { ty::Predicate::Trait(ref data) => { + if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) { + return Ok(Some(vec![])); + } + if coinductive_match(selcx, obligation, data, &backtrace) { return Ok(Some(vec![])); } @@ -426,9 +434,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let trait_obligation = obligation.with(data.clone()); match selcx.select(&trait_obligation) { Ok(Some(vtable)) => { + info!("selecting trait `{:?}` at depth {} yielded Ok(Some)", + data, obligation.recursion_depth); Ok(Some(vtable.nested_obligations())) } Ok(None) => { + info!("selecting trait `{:?}` at depth {} yielded Ok(None)", + data, obligation.recursion_depth); + // This is a bit subtle: for the most part, the // only reason we can fail to make progress on // trait selection is because we don't have enough @@ -457,6 +470,8 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, Ok(None) } Err(selection_err) => { + info!("selecting trait `{:?}` at depth {} yielded Err", + data, obligation.recursion_depth); Err(CodeSelectionError(selection_err)) } } @@ -642,18 +657,28 @@ impl<'tcx> GlobalFulfilledPredicates<'tcx> { pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool { if let ty::Predicate::Trait(ref data) = *key { - // For the global predicate registry, when we find a match, it - // may have been computed by some other task, so we want to - // add a read from the node corresponding to the predicate - // processing to make sure we get the transitive dependencies. - if self.set.contains(data) { - debug_assert!(data.is_global()); - self.dep_graph.read(data.dep_node()); - return true; - } + self.check_duplicate_trait(data) + } else { + false } + } + + pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool { + // For the global predicate registry, when we find a match, it + // may have been computed by some other task, so we want to + // add a read from the node corresponding to the predicate + // processing to make sure we get the transitive dependencies. + if self.set.contains(data) { + debug_assert!(data.is_global()); + self.dep_graph.read(data.dep_node()); + debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data); + + info!("check_duplicate_trait hit: `{:?}`", data); - return false; + true + } else { + false + } } fn add_if_global(&mut self, key: &ty::Predicate<'tcx>) { @@ -663,7 +688,10 @@ impl<'tcx> GlobalFulfilledPredicates<'tcx> { // already has the required read edges, so we don't need // to add any more edges here. if data.is_global() { - self.set.insert(data.clone()); + if self.set.insert(data.clone()) { + debug!("add_if_global: global predicate `{:?}` added", data); + info!("check_duplicate_trait entry: `{:?}`", data); + } } } } diff --git a/src/librustc_data_structures/obligation_forest/README.md b/src/librustc_data_structures/obligation_forest/README.md index 1ffe07bb43b4e..d76d7f6ba340e 100644 --- a/src/librustc_data_structures/obligation_forest/README.md +++ b/src/librustc_data_structures/obligation_forest/README.md @@ -9,15 +9,18 @@ place). `ObligationForest` supports two main public operations (there are a few others not discussed here): -1. Add a new root obligation (`push_root`). +1. Add a new root obligations (`push_tree`). 2. Process the pending obligations (`process_obligations`). When a new obligation `N` is added, it becomes the root of an -obligation tree. This tree is a singleton to start, so `N` is both the -root and the only leaf. Each time the `process_obligations` method is -called, it will invoke its callback with every pending obligation (so -that will include `N`, the first time). The callback shoud process the -obligation `O` that it is given and return one of three results: +obligation tree. This tree can also carry some per-tree state `T`, +which is given at the same time. This tree is a singleton to start, so +`N` is both the root and the only leaf. Each time the +`process_obligations` method is called, it will invoke its callback +with every pending obligation (so that will include `N`, the first +time). The callback also receives a (mutable) reference to the +per-tree state `T`. The callback should process the obligation `O` +that it is given and return one of three results: - `Ok(None)` -> ambiguous result. Obligation was neither a success nor a failure. It is assumed that further attempts to process the diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 0d92a2b158f82..25a77adba2820 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -19,11 +19,16 @@ use std::fmt::Debug; use std::mem; mod node_index; +use self::node_index::NodeIndex; + +mod tree_index; +use self::tree_index::TreeIndex; + #[cfg(test)] mod test; -pub struct ObligationForest { +pub struct ObligationForest { /// The list of obligations. In between calls to /// `process_obligations`, this list only contains nodes in the /// `Pending` or `Success` state (with a non-zero number of @@ -37,6 +42,7 @@ pub struct ObligationForest { /// at a higher index than its parent. This is needed by the /// backtrace iterator (which uses `split_at`). nodes: Vec>, + trees: Vec>, snapshots: Vec } @@ -44,12 +50,15 @@ pub struct Snapshot { len: usize, } -pub use self::node_index::NodeIndex; +struct Tree { + root: NodeIndex, + state: T, +} struct Node { state: NodeState, parent: Option, - root: NodeIndex, // points to the root, which may be the current node + tree: TreeIndex, } /// The state of one node in some tree within the forest. This @@ -99,9 +108,10 @@ pub struct Error { pub backtrace: Vec, } -impl ObligationForest { - pub fn new() -> ObligationForest { +impl ObligationForest { + pub fn new() -> ObligationForest { ObligationForest { + trees: vec![], nodes: vec![], snapshots: vec![] } @@ -114,30 +124,39 @@ impl ObligationForest { } pub fn start_snapshot(&mut self) -> Snapshot { - self.snapshots.push(self.nodes.len()); + self.snapshots.push(self.trees.len()); Snapshot { len: self.snapshots.len() } } pub fn commit_snapshot(&mut self, snapshot: Snapshot) { assert_eq!(snapshot.len, self.snapshots.len()); - let nodes_len = self.snapshots.pop().unwrap(); - assert!(self.nodes.len() >= nodes_len); + let trees_len = self.snapshots.pop().unwrap(); + assert!(self.trees.len() >= trees_len); } pub fn rollback_snapshot(&mut self, snapshot: Snapshot) { // Check that we are obeying stack discipline. assert_eq!(snapshot.len, self.snapshots.len()); - let nodes_len = self.snapshots.pop().unwrap(); + let trees_len = self.snapshots.pop().unwrap(); - // The only action permitted while in a snapshot is to push - // new root obligations. Because no processing will have been - // done, those roots should still be in the pending state. - debug_assert!(self.nodes[nodes_len..].iter().all(|n| match n.state { - NodeState::Pending { .. } => true, - _ => false, - })); + // If nothing happened in snapshot, done. + if self.trees.len() == trees_len { + return; + } - self.nodes.truncate(nodes_len); + // Find root of first tree; because nothing can happen in a + // snapshot but pushing trees, all nodes after that should be + // roots of other trees as well + let first_root_index = self.trees[trees_len].root.get(); + debug_assert!( + self.nodes[first_root_index..] + .iter() + .zip(first_root_index..) + .all(|(root, root_index)| self.trees[root.tree.get()].root.get() == root_index)); + + // Pop off tree/root pairs pushed during snapshot. + self.trees.truncate(trees_len); + self.nodes.truncate(first_root_index); } pub fn in_snapshot(&self) -> bool { @@ -147,9 +166,11 @@ impl ObligationForest { /// Adds a new tree to the forest. /// /// This CAN be done during a snapshot. - pub fn push_root(&mut self, obligation: O) { + pub fn push_tree(&mut self, obligation: O, tree_state: T) { let index = NodeIndex::new(self.nodes.len()); - self.nodes.push(Node::new(index, None, obligation)); + let tree = TreeIndex::new(self.trees.len()); + self.trees.push(Tree { root: index, state: tree_state }); + self.nodes.push(Node::new(tree, None, obligation)); } /// Convert all remaining obligations to the given error. @@ -186,7 +207,7 @@ impl ObligationForest { /// /// This CANNOT be unrolled (presently, at least). pub fn process_obligations(&mut self, mut action: F) -> Outcome - where E: Debug, F: FnMut(&mut O, Backtrace) -> Result>, E> + where E: Debug, F: FnMut(&mut O, &mut T, Backtrace) -> Result>, E> { debug!("process_obligations(len={})", self.nodes.len()); assert!(!self.in_snapshot()); // cannot unroll this action @@ -210,7 +231,7 @@ impl ObligationForest { index, self.nodes[index].state); let result = { - let parent = self.nodes[index].parent; + let Node { tree, parent, .. } = self.nodes[index]; let (prefix, suffix) = self.nodes.split_at_mut(index); let backtrace = Backtrace::new(prefix, parent); match suffix[0].state { @@ -218,7 +239,7 @@ impl ObligationForest { NodeState::Success { .. } => continue, NodeState::Pending { ref mut obligation } => - action(obligation, backtrace), + action(obligation, &mut self.trees[tree.get()].state, backtrace), } }; @@ -268,11 +289,11 @@ impl ObligationForest { self.update_parent(index); } else { // create child work - let root_index = self.nodes[index].root; + let tree_index = self.nodes[index].tree; let node_index = NodeIndex::new(index); self.nodes.extend( children.into_iter() - .map(|o| Node::new(root_index, Some(node_index), o))); + .map(|o| Node::new(tree_index, Some(node_index), o))); } // change state from `Pending` to `Success`, temporarily swapping in `Error` @@ -311,8 +332,9 @@ impl ObligationForest { /// skip the remaining obligations from a tree once some other /// node in the tree is found to be in error. fn inherit_error(&mut self, child: usize) { - let root = self.nodes[child].root.get(); - if let NodeState::Error = self.nodes[root].state { + let tree = self.nodes[child].tree; + let root = self.trees[tree.get()].root; + if let NodeState::Error = self.nodes[root.get()].state { self.nodes[child].state = NodeState::Error; } } @@ -353,7 +375,8 @@ impl ObligationForest { /// indices. Cannot be used during a transaction. fn compress(&mut self) -> Vec { assert!(!self.in_snapshot()); // didn't write code to unroll this action - let mut rewrites: Vec<_> = (0..self.nodes.len()).collect(); + let mut node_rewrites: Vec<_> = (0..self.nodes.len()).collect(); + let mut tree_rewrites: Vec<_> = (0..self.trees.len()).collect(); // Finish propagating error state. Note that in this case we // only have to check immediate parents, rather than all @@ -366,43 +389,69 @@ impl ObligationForest { } } + // Determine which trees to remove by checking if their root + // is popped. + let mut dead_trees = 0; + let trees_len = self.trees.len(); + for i in 0..trees_len { + let root_node = self.trees[i].root; + if self.nodes[root_node.get()].is_popped() { + dead_trees += 1; + } else if dead_trees > 0 { + self.trees.swap(i, i - dead_trees); + tree_rewrites[i] -= dead_trees; + } + } + // Now go through and move all nodes that are either // successful or which have an error over into to the end of // the list, preserving the relative order of the survivors // (which is important for the `inherit_error` logic). - let mut dead = 0; + let mut dead_nodes = 0; for i in 0..nodes_len { if self.nodes[i].is_popped() { - dead += 1; - } else if dead > 0 { - self.nodes.swap(i, i - dead); - rewrites[i] -= dead; + dead_nodes += 1; + } else if dead_nodes > 0 { + self.nodes.swap(i, i - dead_nodes); + node_rewrites[i] -= dead_nodes; } } + // No compression needed. + if dead_nodes == 0 && dead_trees == 0 { + return vec![]; + } + + // Pop off the trees we killed. + self.trees.truncate(trees_len - dead_trees); + // Pop off all the nodes we killed and extract the success // stories. let successful = - (0 .. dead).map(|_| self.nodes.pop().unwrap()) - .flat_map(|node| match node.state { - NodeState::Error => None, - NodeState::Pending { .. } => unreachable!(), - NodeState::Success { obligation, num_incomplete_children } => { - assert_eq!(num_incomplete_children, 0); - Some(obligation) - } - }) - .collect(); - - // Adjust the parent indices, since we compressed things. + (0 .. dead_nodes) + .map(|_| self.nodes.pop().unwrap()) + .flat_map(|node| match node.state { + NodeState::Error => None, + NodeState::Pending { .. } => unreachable!(), + NodeState::Success { obligation, num_incomplete_children } => { + assert_eq!(num_incomplete_children, 0); + Some(obligation) + } + }) + .collect(); + + // Adjust the various indices, since we compressed things. + for tree in &mut self.trees { + tree.root = NodeIndex::new(node_rewrites[tree.root.get()]); + } for node in &mut self.nodes { if let Some(ref mut index) = node.parent { - let new_index = rewrites[index.get()]; - debug_assert!(new_index < (nodes_len - dead)); + let new_index = node_rewrites[index.get()]; + debug_assert!(new_index < (nodes_len - dead_nodes)); *index = NodeIndex::new(new_index); } - node.root = NodeIndex::new(rewrites[node.root.get()]); + node.tree = TreeIndex::new(tree_rewrites[node.tree.get()]); } successful @@ -410,11 +459,11 @@ impl ObligationForest { } impl Node { - fn new(root: NodeIndex, parent: Option, obligation: O) -> Node { + fn new(tree: TreeIndex, parent: Option, obligation: O) -> Node { Node { parent: parent, state: NodeState::Pending { obligation: obligation }, - root: root + tree: tree, } } diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs index 519b282a6a8c7..9a0a4218d4593 100644 --- a/src/librustc_data_structures/obligation_forest/test.rs +++ b/src/librustc_data_structures/obligation_forest/test.rs @@ -13,22 +13,24 @@ use super::{ObligationForest, Outcome, Error}; #[test] fn push_pop() { let mut forest = ObligationForest::new(); - forest.push_root("A"); - forest.push_root("B"); - forest.push_root("C"); + forest.push_tree("A", "A"); + forest.push_tree("B", "B"); + forest.push_tree("C", "C"); // first round, B errors out, A has subtasks, and C completes, creating this: // A |-> A.1 // |-> A.2 // |-> A.3 - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, _| { - match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), - "B" => Err("B is for broken"), - "C" => Ok(Some(vec![])), - _ => unreachable!(), - } - }); + let Outcome { completed: ok, errors: err, .. } = + forest.process_obligations(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "B" => Err("B is for broken"), + "C" => Ok(Some(vec![])), + _ => unreachable!(), + } + }); assert_eq!(ok, vec!["C"]); assert_eq!(err, vec![Error {error: "B is for broken", backtrace: vec!["B"]}]); @@ -39,9 +41,10 @@ fn push_pop() { // |-> A.3 |-> A.3.i // D |-> D.1 // |-> D.2 - forest.push_root("D"); + forest.push_tree("D", "D"); let Outcome { completed: ok, errors: err, .. }: Outcome<&'static str, ()> = - forest.process_obligations(|obligation, _| { + forest.process_obligations(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.1" => Ok(None), "A.2" => Ok(None), @@ -58,26 +61,30 @@ fn push_pop() { // propagates to A.3.i, but not D.1 or D.2. // D |-> D.1 |-> D.1.i // |-> D.2 |-> D.2.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, _| { - match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Err("A is for apple"), - "D.1" => Ok(Some(vec!["D.1.i"])), - "D.2" => Ok(Some(vec!["D.2.i"])), - _ => unreachable!(), - } - }); + let Outcome { completed: ok, errors: err, .. } = + forest.process_obligations(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "A.1" => Ok(Some(vec![])), + "A.2" => Err("A is for apple"), + "D.1" => Ok(Some(vec!["D.1.i"])), + "D.2" => Ok(Some(vec!["D.2.i"])), + _ => unreachable!(), + } + }); assert_eq!(ok, vec!["A.1"]); assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]); // fourth round: error in D.1.i that should propagate to D.2.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, _| { - match *obligation { - "D.1.i" => Err("D is for dumb"), - _ => panic!("unexpected obligation {:?}", obligation), - } - }); + let Outcome { completed: ok, errors: err, .. } = + forest.process_obligations(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "D.1.i" => Err("D is for dumb"), + _ => panic!("unexpected obligation {:?}", obligation), + } + }); assert_eq!(ok, Vec::<&'static str>::new()); assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]); @@ -94,10 +101,11 @@ fn push_pop() { #[test] fn success_in_grandchildren() { let mut forest = ObligationForest::new(); - forest.push_root("A"); + forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, _| { + forest.process_obligations::<(),_>(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), _ => unreachable!(), @@ -107,7 +115,8 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, _| { + forest.process_obligations::<(),_>(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.1" => Ok(Some(vec![])), "A.2" => Ok(Some(vec!["A.2.i", "A.2.ii"])), @@ -119,7 +128,8 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, _| { + forest.process_obligations::<(),_>(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.2.i" => Ok(Some(vec!["A.2.i.a"])), "A.2.ii" => Ok(Some(vec![])), @@ -130,7 +140,8 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, _| { + forest.process_obligations::<(),_>(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.2.i.a" => Ok(Some(vec![])), _ => unreachable!(), @@ -140,7 +151,7 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|_, _| unreachable!()); + forest.process_obligations::<(),_>(|_, _, _| unreachable!()); assert!(ok.is_empty()); assert!(err.is_empty()); } @@ -150,9 +161,10 @@ fn to_errors_no_throw() { // check that converting multiple children with common parent (A) // only yields one of them (and does not panic, in particular). let mut forest = ObligationForest::new(); - forest.push_root("A"); + forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, _| { + forest.process_obligations::<(),_>(|obligation, tree, _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), _ => unreachable!(), @@ -168,10 +180,11 @@ fn to_errors_no_throw() { fn backtrace() { // check that converting multiple children with common parent (A) // only yields one of them (and does not panic, in particular). - let mut forest: ObligationForest<&'static str> = ObligationForest::new(); - forest.push_root("A"); + let mut forest = ObligationForest::new(); + forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, mut backtrace| { + forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().is_none()); match *obligation { "A" => Ok(Some(vec!["A.1"])), @@ -181,7 +194,8 @@ fn backtrace() { assert!(ok.is_empty()); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, mut backtrace| { + forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().unwrap() == &"A"); assert!(backtrace.next().is_none()); match *obligation { @@ -192,7 +206,8 @@ fn backtrace() { assert!(ok.is_empty()); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, mut backtrace| { + forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().unwrap() == &"A.1"); assert!(backtrace.next().unwrap() == &"A"); assert!(backtrace.next().is_none()); diff --git a/src/librustc_data_structures/obligation_forest/tree_index.rs b/src/librustc_data_structures/obligation_forest/tree_index.rs new file mode 100644 index 0000000000000..a9f5483f45b3e --- /dev/null +++ b/src/librustc_data_structures/obligation_forest/tree_index.rs @@ -0,0 +1,28 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::u32; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TreeIndex { + index: u32 +} + +impl TreeIndex { + pub fn new(value: usize) -> TreeIndex { + assert!(value < (u32::MAX as usize)); + TreeIndex { index: value as u32 } + } + + pub fn get(self) -> usize { + self.index as usize + } +} +