/*! Generate files suitable for use with [Graphviz](http://www.graphviz.org/)
-The `render` function generates output (e.g. a `output.dot` file) for
+The `render` function generates output (e.g. an `output.dot` file) for
use with [Graphviz](http://www.graphviz.org/) by walking a labelled
graph. (Graphviz can then automatically lay out the nodes and edges
of the graph, and also optionally render the graph as an image or
Each node label is derived directly from the int representing the node,
while the edge labels are all empty strings.
-This example also illustrates how to use the `Borrowed` variant of
-`MaybeOwnedVector` to return a slice into the edge list, rather than
-constructing a copy from scratch.
+This example also illustrates how to use `MaybeOwnedVector` to return
+an owned vector or a borrowed slice as appropriate: we construct the
+node vector from scratch, but borrow the edge list (rather than
+constructing a copy of all the edges from scratch).
The output from this example renders five nodes, with the first four
forming a diamond-shaped acyclic graph and then pointing to the fifth
```rust
use dot = graphviz;
+use graphviz::maybe_owned_vec::IntoMaybeOwnedVector;
type Nd = int;
type Ed = (int,int);
}
nodes.sort();
nodes.dedup();
- nodes.move_iter().collect()
+ nodes.into_maybe_owned()
}
fn edges(&'a self) -> dot::Edges<'a,Ed> {
let &Edges(ref edges) = self;
- dot::maybe_owned_vec::Borrowed(edges.as_slice())
+ edges.as_slice().into_maybe_owned()
}
fn source(&self, e: &Ed) -> Nd { let &(s,_) = e; s }
type) that shares substructure with the graph: the edge type here is a
direct reference to the `(source,target)` pair stored in the graph's
internal vector (rather than passing around a copy of the pair
-itself). Note that in this case, this implies that `fn edges(&'a
-self)` must construct a fresh `Vec<&'a (uint,uint)>` from the
-`Vec<(uint,uint)>` edges stored in `self`.
+itself). Note that this implies that `fn edges(&'a self)` must
+construct a fresh `Vec<&'a (uint,uint)>` from the `Vec<(uint,uint)>`
+edges stored in `self`.
+
+Since both the set of nodes and the set of edges are always
+constructed from scratch via iterators, we use the `collect()` method
+from the `Iterator` trait to collect the nodes and edges into freshly
+constructed growable `Vec` values (rather use the `into_maybe_owned`
+from the `IntoMaybeOwnedVector` trait as was used in the first example
+above).
The output from this example renders four nodes that make up the
Hasse-diagram for the subsets of the set `{x, y}`. Each edge is
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::container::Container;
+use std::fmt;
use std::iter::FromIterator;
use std::slice;
-// Note: Once Dynamically Sized Types (DST) lands, this should be
-// replaced with something like `enum Owned<'a, Sized? U>{ Owned(~U),
-// Borrowed(&'a U) }`; and then `U` could be instantiated with `[T]`
-// or `str`, etc.
+// Note 1: It is not clear whether the flexibility of providing both
+// the `Growable` and `FixedLen` variants is sufficiently useful.
+// Consider restricting to just a two variant enum.
-/// MaybeOwnedVector<'a,T> abstracts over `Vec<T>` and `&'a [T]`.
+// Note 2: Once Dynamically Sized Types (DST) lands, it might be
+// reasonable to replace this with something like `enum MaybeOwned<'a,
+// Sized? U>{ Owned(~U), Borrowed(&'a U) }`; and then `U` could be
+// instantiated with `[T]` or `str`, etc. Of course, that would imply
+// removing the `Growable` variant, which relates to note 1 above.
+// Alternatively, we might add `MaybeOwned` for the general case but
+// keep some form of `MaybeOwnedVector` to avoid unnecessary copying
+// of the contents of `Vec<T>`, since we anticipate that to be a
+// frequent way to dynamically construct a vector.
+
+/// MaybeOwnedVector<'a,T> abstracts over `Vec<T>`, `~[T]`, `&'a [T]`.
///
/// Some clients will have a pre-allocated vector ready to hand off in
/// a slice; others will want to create the set on the fly and hand
-/// off ownership.
-#[deriving(Eq)]
+/// off ownership, via either `Growable` or `FixedLen` depending on
+/// which kind of vector they have constucted. (The `FixedLen`
+/// variant is provided for interoperability with `std::slice` methods
+/// that return `~[T]`.)
pub enum MaybeOwnedVector<'a,T> {
Growable(Vec<T>),
+ FixedLen(~[T]),
Borrowed(&'a [T]),
}
+/// Trait for moving into a `MaybeOwnedVector`
+pub trait IntoMaybeOwnedVector<'a,T> {
+ /// Moves self into a `MaybeOwnedVector`
+ fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T>;
+}
+
+impl<'a,T> IntoMaybeOwnedVector<'a,T> for Vec<T> {
+ #[inline]
+ fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Growable(self) }
+}
+
+impl<'a,T> IntoMaybeOwnedVector<'a,T> for ~[T] {
+ #[inline]
+ fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { FixedLen(self) }
+}
+
+impl<'a,T> IntoMaybeOwnedVector<'a,T> for &'a [T] {
+ #[inline]
+ fn into_maybe_owned(self) -> MaybeOwnedVector<'a,T> { Borrowed(self) }
+}
+
impl<'a,T> MaybeOwnedVector<'a,T> {
pub fn iter(&'a self) -> slice::Items<'a,T> {
match self {
&Growable(ref v) => v.iter(),
+ &FixedLen(ref v) => v.iter(),
&Borrowed(ref v) => v.iter(),
}
}
}
-impl<'a,T> Container for MaybeOwnedVector<'a,T> {
- fn len(&self) -> uint {
- match self {
- &Growable(ref v) => v.len(),
- &Borrowed(ref v) => v.len(),
- }
- }
-}
-
// The `Vector` trait is provided in the prelude and is implemented on
// both `&'a [T]` and `Vec<T>`, so it makes sense to try to support it
// seamlessly. The other vector related traits from the prelude do
fn as_slice<'a>(&'a self) -> &'a [T] {
match self {
&Growable(ref v) => v.as_slice(),
+ &FixedLen(ref v) => v.as_slice(),
&Borrowed(ref v) => v.as_slice(),
}
}
impl<'a,T> FromIterator<T> for MaybeOwnedVector<'a,T> {
fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeOwnedVector<T> {
+ // If we are building from scratch, might as well build the
+ // most flexible variant.
Growable(FromIterator::from_iter(iterator))
}
}
+
+impl<'a,T:fmt::Show> fmt::Show for MaybeOwnedVector<'a,T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.as_slice().fmt(f)
+ }
+}
+
+impl<'a,T:Clone> CloneableVector<T> for MaybeOwnedVector<'a,T> {
+ /// Returns a copy of `self`.
+ fn to_owned(&self) -> ~[T] {
+ self.as_slice().to_owned()
+ }
+
+ /// Convert `self` into an owned slice, not making a copy if possible.
+ fn into_owned(self) -> ~[T] {
+ match self {
+ Growable(v) => v.as_slice().to_owned(),
+ FixedLen(v) => v,
+ Borrowed(v) => v.to_owned(),
+ }
+ }
+}
+
+impl<'a,T:Clone> MaybeOwnedVector<'a,T> {
+ /// Convert `self` into a growable `Vec`, not making a copy if possible.
+ pub fn into_vec(self) -> Vec<T> {
+ match self {
+ Growable(v) => v,
+ FixedLen(v) => Vec::from_slice(v.as_slice()),
+ Borrowed(v) => Vec::from_slice(v),
+ }
+ }
+}