Generator

Struct Generator 

Source
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::marker is called exactly once to determine the diagram marker for the minimal vertex.
  • Ramify::annotate is called exactly once called to determine the annotation for the minimal vertex.
  • Ramify::ramify is called exactly once to replace the current minimal vertex with its children
  • Ramify::sort_key is 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>

Source

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.

Source

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.

Source

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:

  1. The annotation lines (if any), with the vertex on the first or last line depending on the configuration.
  2. Rows for the row padding (if not last).
  3. Any extra rows to prepare for the next vertex (if not last). This includes merge lines, if merges are required.
Source

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.

Source

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.

Source

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.

Source

pub fn branch_diagram(self, style: Style) -> String
where R: Ramify<V>,

Generate the entire branch diagram as a newly allocated string.

This is identical to calling write_all with a FmtWriter wrapping a string.

Source

pub fn config(&self) -> Config

Get a copy of the current configuration.

Source

pub fn set_config(&mut self, config: Config)

Set the configuration to a new value.

Source

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     1
Source

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.

Source

pub fn is_empty(&self) -> bool

Whether or not there are any active vertices.

Source

pub fn into_active_vertices(self) -> impl ExactSizeIterator<Item = V>

Consume the generator, returning an iterator over the active vertices in an unspecified order.

Source

pub fn shrink_to_fit(&mut self)

Shrink the capacity of internal allocations as much as possible.

Source

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.

Trait Implementations§

Source§

impl<V: Debug, R: Debug> Debug for Generator<V, R>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<V, R> Freeze for Generator<V, R>
where R: Freeze,

§

impl<V, R> RefUnwindSafe for Generator<V, R>

§

impl<V, R> Send for Generator<V, R>
where R: Send, V: Send,

§

impl<V, R> Sync for Generator<V, R>
where R: Sync, V: Sync,

§

impl<V, R> Unpin for Generator<V, R>
where R: Unpin, V: Unpin,

§

impl<V, R> UnwindSafe for Generator<V, R>
where R: UnwindSafe, V: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.