pub struct Generator<V, R> { /* private fields */ }Expand description
A generator which incrementally writes the branch diagram to a writer.
Once you have a Ramify impementation, initialize this struct with the new method or from layout configuration. After initializing, the branch
diagram can be incrementally written to a diagram writer using the
write_next or try_write_next methods.
§Layout and style configuration
This struct can be configured by passing an appropriate Config struct. This is layout
configuration. The appearance of the resulting diagram is defined by the diagram writer. The
build in diagram writers (IOWriter and
FmtWriter) use the Style struct for configuration.
It is possible to modify configuration while writing the diagram (that is, in between calls to
write_next) by using set_config.
§Interaction with the Ramify trait.
§Method call guarantees
When a Ramify implementation is used by a Generator, the following calls are made
when rendering a row and its annotation (a single call to
write_next).
Ramify::markeris called exactly once to determine the diagram marker for the minimal vertex.Ramify::annotateis called exactly once called to determine the annotation for the minimal vertex.Ramify::ramifyis called exactly once to replace the current minimal vertex with its childrenRamify::sort_keyis called once for every active vertex every time a new vertex is generated.
Moreover, the call to Ramify::ramify is guaranteed to be last for each vertex.
The other methods only take a reference to the vertex rather than receive the vertex itself.
Otherwise, the relative order between these calls, and moreover the order relative to writes, is unspecified.
§Resource management
The vertex type V can either be borrowed or owned. If you are iterating over an in-memory
recursive type like
struct Vtx<T>(T, Vec<Vtx<T>>);or an equivalent flattened version, then V is probably a lightweight type like &'t Vtx or a
usize index.
If the vertices are loaded in a streaming fashion, then most likely V is an owned type and
therefore it is managed by the generator.
Internally, the generator maintains a list of active vertices: the vertices not yet drawn to
the diagram, but for which a parent has already been drawn to the diagram. Once a vertex has
been drawn to the diagram, it is passed to Ramify::ramify or TryRamify::try_ramify,
which takes ownership of V.
You can recover the active vertices using into_active_vertices.
§Runtime and memory complexity
The branch diagram generator holds the minimal possible state required to generate the diagram.
This state is essentially the active vertices plus additional metadata concerning the column to which the vertex belongs in the diagram and whether the vertex is minimal.
More precisely, the memory usage is (8 + size_of<V>) * num_active_vertices,
plus the maximum size of a single annotation, plus a constant.
Writing a branch diagram row only requires making a finite number of passes over the list of vertices.
Therefore the runtime to write a single branch diagram row is O(num_active_vertices),
assuming the various methods in Ramify take constant time.
If an annotation is written, the entire annotation is loaded into a scratch buffer. The scratch
buffer is re-used between calls to write_next.
Implementations§
Source§impl<V, R> Generator<V, R>
impl<V, R> Generator<V, R>
Sourcepub fn new(root: V, ramifier: R) -> Self
pub fn new(root: V, ramifier: R) -> Self
Get a new branch diagram generator starting at a given vertex of type V using default
configuration.
Sourcepub fn with_config(root: V, ramifier: R, config: Config) -> Self
pub fn with_config(root: V, ramifier: R, config: Config) -> Self
Get a new branch diagram generator starting at a given vertex of type V using the provided
configuration.
Sourcepub fn write_next<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<Self, W::Error>where
R: Ramify<V>,
pub fn write_next<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<Self, W::Error>where
R: Ramify<V>,
Write a row containing a vertex along with its annotation to the provided diagram writer.
This method takes ownership since a write error leaves the generator in an unspecified state from which resuming generation is not possible.
If the generator is empty, this does nothing.
§Output rows
A single call to this method writes the following:
- The annotation lines (if any), with the vertex on the first or last line depending on the configuration.
- Rows for the row padding (if not last).
- Any extra rows to prepare for the next vertex (if not last). This includes merge lines, if merges are required.
Sourcepub fn try_write_next<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<State<V, R, R::Error>, W::Error>where
R: TryRamify<V>,
pub fn try_write_next<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<State<V, R, R::Error>, W::Error>where
R: TryRamify<V>,
Try to write the next vertex, failing to do so if the call to TryRamify::try_ramify
results in an error.
The error is handled eagerly: no writes are performed when an error is encountered. An error puts the generator into a suspended state, and iteration can be continued by supplying a (possibly empty) list of children.
If the generator is empty, this does nothing.
Sourcepub fn write_all<W: DiagramWrite>(self, writer: &mut W) -> Result<(), W::Error>where
R: Ramify<V>,
pub fn write_all<W: DiagramWrite>(self, writer: &mut W) -> Result<(), W::Error>where
R: Ramify<V>,
Write the entire branch diagram into the provided diagram writer.
This repeatedly calls write_next as long as the there are
remaining vertices.
Sourcepub fn try_write_all<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<Option<(SuspendedGenerator<V, R>, R::Error)>, W::Error>where
R: TryRamify<V>,
pub fn try_write_all<W: DiagramWrite>(
self,
writer: &mut W,
) -> Result<Option<(SuspendedGenerator<V, R>, R::Error)>, W::Error>where
R: TryRamify<V>,
Try to write the entire branch diagram into the provided diagram writer.
This repeatedly calls try_write_next as long as the writes succeed. If a
write fails, the suspended generator is returned along with the error which occurred.
Sourcepub fn branch_diagram(self, style: Style) -> Stringwhere
R: Ramify<V>,
pub fn branch_diagram(self, style: Style) -> Stringwhere
R: Ramify<V>,
Sourcepub fn set_config(&mut self, config: Config)
pub fn set_config(&mut self, config: Config)
Set the configuration to a new value.
Sourcepub fn max_edge_index(&self) -> Option<usize>
pub fn max_edge_index(&self) -> Option<usize>
The index of the largest occupied column, or None if the diagram is empty.
For example, the below diagrams have maximum edge index 4 and 1 respectively.
0 0
├┬╮ ├┬╮
│1│ │1│
├╮╰─╮ │╭╯
^ ^
4 1Sourcepub fn num_active_vertices(&self) -> usize
pub fn num_active_vertices(&self) -> usize
The number of active vertices.
An active vertex is a vertex which has not yet been written to the branch diagram, but whose parent was already written. Since multiple vertices may use the same edge, this number is distinct from the number of outgoing edges.
The count will include equivalent vertices, excluding those that are equivalent to the current minimal vertex.
Sourcepub fn into_active_vertices(self) -> impl ExactSizeIterator<Item = V>
pub fn into_active_vertices(self) -> impl ExactSizeIterator<Item = V>
Consume the generator, returning an iterator over the active vertices in an unspecified order.
Sourcepub fn shrink_to_fit(&mut self)
pub fn shrink_to_fit(&mut self)
Shrink the capacity of internal allocations as much as possible.
Sourcepub fn previous_annotation(&self) -> &str
pub fn previous_annotation(&self) -> &str
The annotation of the previous vertex, if any.
This returns the empty string if there was no previous vertex or if the previous vertex did not have an annotation.