Struct midenc_hir_transform::Treeify

source ·
pub struct Treeify;
Expand description

This pass rewrites the CFG of a function so that it forms a tree.

While we technically call this treeification, the CFG cannot be fully converted into a tree in general, as loops must be preserved (they can be copied along multiple control flow paths, but we want to preserve the loop structure in the CFG).

The treeify transformation concerns itself with any block B which has multiple predecessors in the control flow graph, where for at least two of those predecessors, the predecessor is always visited before B, if control flows through both. This is a slightly less restrictive conditon than the dominance property, but is very much related - the primary difference being that unlike dominance, what we are capturing is that the predecessor block is not along a loopback edge. It is quite common for a predecessor block to always be visited first in the CFG, while not dominating its successor: consider an if/else expression, where control splits at the if/else, and rejoins afterwards, the code in the final block where control is joined can only be reached after either the if or else block has executed, but neither the if nor the else blocks can be considered to “dominate” the final block in the graph theoretical sense.

The actual treeification process works like so:

  1. For each block B, in the postorder sort of the CFG, determine if B has more than one predecessor P, where P appears before B in the reverse postorder sort of the CFG. a. If found, treeify the block as described in subsequent steps b. Otherwise, ignore this block and proceed
  2. For each P, clone B to a new block B’, and rewrite P such that it branches to B’ rather than B.
  3. For each successor S of B: a. If S is a loop header, and S appears before B in the reverse postorder sort of the CFG, then it is a loopback edge, so the corresponding edge from B’ to S is left intact. b. If S is a loop header, but S appears after B in the reverse postorder sort of the CFG, then it is treated like other blocks (see c.) c. Otherwise, clone S to S’, and rewrite B’ to branch to S’ instead of S.
  4. Repeat step 2 for the successors of S, recursively, until the subgraph reachable from B

Since we are treeifying blocks from the leaves of the CFG to the root, and because we do not follow loopback edges which escape/continue an outer loop - whenever we clone a subgraph of the CFG, we know that it has already been treeified, as we only start to treeify a block once all of the blocks reachable via that block have been treeified.

In short, we’re trying to split blocks with multiple predecessors such that all blocks have either zero or one predecessors, i.e. the CFG forms a tree. As mentioned previously, we must make an exception for loop headers, which by definition must have at least one predecessor which is a loopback edge, but this suits us just fine, as Miden Assembly provides control flow instructions compatible with lowering from such a CFG.

§Examples

§Basic DAG

This example demonstrates how the DAG of a function with multiple returns gets transformed:

blk0
 |
 v
blk1 -> blk3 -> ret
 |     /
 |    /
 |   /
 v  v
blk2
 |
 v
ret

Becomes:

blk0
 |
 v
blk1 -> blk3 -> ret
 |       |
 |       |
 |       |
 v       v
blk2    blk2
 |       |
 v       v
ret     ret

§Basic Loop

This is an example of a function with multiple returns and a simple loop:

blk0
 |                -------
 v               v       |
blk1 -> blk3 -> blk4 -> blk5 -> ret
 |     /
 |    /
 |   /
 v  v
blk2
 |
 v
ret

Becomes:

blk0
 |                -------
 v               v       |
blk1 -> blk3 -> blk4 -> blk5 -> ret
 |       |
 |       |
 |       |
 v       v
blk2    blk2
 |       |
 v       v
ret     ret

§Complex Loop

This is an example of a function with a complex loop (i.e. multiple exit points):

blk0
 |
 v
blk1
 |  \
 |   blk2 <-----
 |    |         |
 |   blk3       |
 |   /   \      |
 |  /     blk4--
 | /       |
 vv        |
blk5      blk6

Becomes:

blk0
 |
 v
blk1
 |  \
 |   \
 |    blk2 <---
 |     |       |
 |     v       |
 |    blk3     |
 |    |  \     |
 |    |   blk4--
 |    |    |
 v    v    v
blk5 blk5  blk6

NOTE: Here, when generating code for blk5 and blk6, the loop depth is 0, so we will emit a single push.0 at the end of both blocks which will terminate the containing loop, and then return from the function as we’ve reached the bottom of the tree.

§Nested Loops

This is an extension of the example above, but with nested loops:

blk0
 |
 v
blk1
 |  \
 |   blk2 <-------
 |    |         | |
 |   blk3       | |
 |   /   \      | |
 |  /     blk4--  |
 | /       |      |
 vv        v      |
blk5<-    blk6-->blk7-->blk8
      |    ^             |
      |    |_____________|
      |                  |
      |__________________|

We have two loops, the outer one starting at blk2:

  • blk2->blk3->blk4->blk2
  • blk2->blk3->blk4->blk6->blk7->blk2

And the inner one starting at blk6:

  • blk6->blk7->blk8->blk6

Additionally, there are multiple exits through the loops, depending on the path taken:

  • blk2->blk3->blk5
  • blk2->blk3->blk4->blk6->blk7->blk8->blk5
  • blk6->blk7->blk8->blk5

After transformation, this becomes:

blk0
 |
 v
blk1
 |  \
 |   blk2 <-------
 |    |         | |
 |   blk3       | |
 |    |  \      | |
 |    |   blk4--  |
 |    |    |      |
 v    v    v      |
blk5 blk5 blk6-->blk7-->blk8
           ^             | |
           |_____________|_|
                         |
                         v
                        blk5

During codegen though, we end up with the following tree of stack machine code.

At each point where control flow either continues a loop or leaves it, we must

  • Duplicate loop headers on control flow edges leading to those headers
  • Emit N push.0 instructions on control flow edges exiting the function from a loop depth of N
  • Emit a combination of the above on control flow edges exiting an inner loop for an outer loop, depending on what depths the predecessor and successor blocks are at
blk0
blk1
if.true
  blk2
  while.true
    blk3
    if.true
      blk4
      if.true
        blk2         # duplicated outer loop header
      else
        blk6
        while.true
          blk7
          if.true
            blk2     # duplicated outer loop header
            push.0   # break out of inner loop
          else
            blk8
            if.true
              blk6   # duplicated inner loop header
            else
              blk5
              push.0 # break out of outer loop
              push.0 # break out of inner loop
            end
          end
        end
      end
    else
      blk5
      push.0         # break out of outer loop
    end
  end
else
  blk5
end

Trait Implementations§

source§

impl Default for Treeify

source§

fn default() -> Treeify

Returns the “default value” for a type. Read more
source§

impl PassInfo for Treeify

source§

const FLAG: &'static str = Treeify

The string which should be used as the name of this pass on the command line. Read more
source§

const SUMMARY: &'static str = /// This pass rewrites the CFG of a function so that it forms a tree. /// /// While we technically call this treeification, the CFG cannot be fully converted into a /// tree in general, as loops must be preserved (they can be copied along multiple control /// flow paths, but we want to preserve the loop structure in the CFG). /// /// The treeify transformation concerns itself with any block B which has multiple predecessors /// in the control flow graph, where for at least two of those predecessors, the predecessor is /// always visited before B, if control flows through both. This is a slightly less restrictive /// conditon than the dominance property, but is very much related - the primary difference being /// that unlike dominance, what we are capturing is that the predecessor block is not along a /// loopback edge. It is quite common for a predecessor block to always be visited first in the /// CFG, while not dominating its successor: consider an if/else expression, where control splits /// at the `if/else`, and rejoins afterwards, the code in the final block where control is joined /// can only be reached after either the `if` or `else` block has executed, but neither the `if` /// nor the `else` blocks can be considered to "dominate" the final block in the graph theoretical /// sense. /// /// The actual treeification process works like so: /// /// 1. For each block B, in the postorder sort of the CFG, determine if B has more than one /// predecessor P, where P appears before B in the reverse postorder sort of the CFG. a. If /// found, treeify the block as described in subsequent steps b. Otherwise, ignore this block and /// proceed /// 2. For each P, clone B to a new block B', and rewrite P such that it branches to B' rather than /// B. /// 3. For each successor S of B: /// a. If S is a loop header, and S appears before B in the reverse postorder sort of the CFG, /// then it is a loopback edge, so the corresponding edge from B' to S is left intact. /// b. If S is a loop header, but S appears after B in the reverse postorder sort of the CFG, /// then it is treated like other blocks (see c.) /// c. Otherwise, clone S to S', and rewrite B' to branch to S' instead of S. /// 4. Repeat step 2 for the successors of S, recursively, until the subgraph reachable from B /// /// Since we are treeifying blocks from the leaves of the CFG to the root, and because we do not /// follow loopback edges which escape/continue an outer loop - whenever we clone a subgraph of /// the CFG, we know that it has already been treeified, as we only start to treeify a block once /// all of the blocks reachable via that block have been treeified. /// /// In short, we're trying to split blocks with multiple predecessors such that all blocks have /// either zero or one predecessors, i.e. the CFG forms a tree. As mentioned previously, we must /// make an exception for loop headers, which by definition must have at least one predecessor /// which is a loopback edge, but this suits us just fine, as Miden Assembly provides control flow /// instructions compatible with lowering from such a CFG. /// /// # Examples /// /// ## Basic DAG /// /// This example demonstrates how the DAG of a function with multiple returns gets transformed: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 -> blk3 -> ret /// | / /// | / /// | / /// v v /// blk2 /// | /// v /// ret /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 -> blk3 -> ret /// | | /// | | /// | | /// v v /// blk2 blk2 /// | | /// v v /// ret ret /// ``` /// /// ## Basic Loop /// /// This is an example of a function with multiple returns and a simple loop: /// /// ```text,ignore /// blk0 /// | ------- /// v v | /// blk1 -> blk3 -> blk4 -> blk5 -> ret /// | / /// | / /// | / /// v v /// blk2 /// | /// v /// ret /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | ------- /// v v | /// blk1 -> blk3 -> blk4 -> blk5 -> ret /// | | /// | | /// | | /// v v /// blk2 blk2 /// | | /// v v /// ret ret /// ``` /// /// ## Complex Loop /// /// This is an example of a function with a complex loop (i.e. multiple exit points): /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <----- /// | | | /// | blk3 | /// | / \ | /// | / blk4-- /// | / | /// vv | /// blk5 blk6 /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | \ /// | blk2 <--- /// | | | /// | v | /// | blk3 | /// | | \ | /// | | blk4-- /// | | | /// v v v /// blk5 blk5 blk6 /// ``` /// /// NOTE: Here, when generating code for `blk5` and `blk6`, the loop depth is 0, so /// we will emit a single `push.0` at the end of both blocks which will terminate the /// containing loop, and then return from the function as we've reached the bottom /// of the tree. /// /// ## Nested Loops /// /// This is an extension of the example above, but with nested loops: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <------- /// | | | | /// | blk3 | | /// | / \ | | /// | / blk4-- | /// | / | | /// vv v | /// blk5<- blk6-->blk7-->blk8 /// | ^ | /// | |_____________| /// | | /// |__________________| /// ``` /// /// We have two loops, the outer one starting at `blk2`: /// /// * `blk2->blk3->blk4->blk2` /// * `blk2->blk3->blk4->blk6->blk7->blk2` /// /// And the inner one starting at `blk6`: /// /// * `blk6->blk7->blk8->blk6` /// /// Additionally, there are multiple exits through the loops, depending on the path taken: /// /// * `blk2->blk3->blk5` /// * `blk2->blk3->blk4->blk6->blk7->blk8->blk5` /// * `blk6->blk7->blk8->blk5` /// /// After transformation, this becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <------- /// | | | | /// | blk3 | | /// | | \ | | /// | | blk4-- | /// | | | | /// v v v | /// blk5 blk5 blk6-->blk7-->blk8 /// ^ | | /// |_____________|_| /// | /// v /// blk5 /// ``` /// /// During codegen though, we end up with the following tree of stack machine code. /// /// At each point where control flow either continues a loop or leaves it, we must /// /// * Duplicate loop headers on control flow edges leading to those headers /// * Emit N `push.0` instructions on control flow edges exiting the function from a loop depth of N /// * Emit a combination of the above on control flow edges exiting an inner loop for an outer loop, /// depending on what depths the predecessor and successor blocks are at /// /// ```text,ignore /// blk0 /// blk1 /// if.true /// blk2 /// while.true /// blk3 /// if.true /// blk4 /// if.true /// blk2 # duplicated outer loop header /// else /// blk6 /// while.true /// blk7 /// if.true /// blk2 # duplicated outer loop header /// push.0 # break out of inner loop /// else /// blk8 /// if.true /// blk6 # duplicated inner loop header /// else /// blk5 /// push.0 # break out of outer loop /// push.0 # break out of inner loop /// end /// end /// end /// end /// else /// blk5 /// push.0 # break out of outer loop /// end /// end /// else /// blk5 /// end /// ``` #[derive(Default, PassInfo, ModuleRewritePassAdapter)] pub struct Treeify;

A short, single-line description of what this pass does. Read more
source§

const DESCRIPTION: &'static str = /// This pass rewrites the CFG of a function so that it forms a tree. /// /// While we technically call this treeification, the CFG cannot be fully converted into a /// tree in general, as loops must be preserved (they can be copied along multiple control /// flow paths, but we want to preserve the loop structure in the CFG). /// /// The treeify transformation concerns itself with any block B which has multiple predecessors /// in the control flow graph, where for at least two of those predecessors, the predecessor is /// always visited before B, if control flows through both. This is a slightly less restrictive /// conditon than the dominance property, but is very much related - the primary difference being /// that unlike dominance, what we are capturing is that the predecessor block is not along a /// loopback edge. It is quite common for a predecessor block to always be visited first in the /// CFG, while not dominating its successor: consider an if/else expression, where control splits /// at the `if/else`, and rejoins afterwards, the code in the final block where control is joined /// can only be reached after either the `if` or `else` block has executed, but neither the `if` /// nor the `else` blocks can be considered to "dominate" the final block in the graph theoretical /// sense. /// /// The actual treeification process works like so: /// /// 1. For each block B, in the postorder sort of the CFG, determine if B has more than one /// predecessor P, where P appears before B in the reverse postorder sort of the CFG. a. If /// found, treeify the block as described in subsequent steps b. Otherwise, ignore this block and /// proceed /// 2. For each P, clone B to a new block B', and rewrite P such that it branches to B' rather than /// B. /// 3. For each successor S of B: /// a. If S is a loop header, and S appears before B in the reverse postorder sort of the CFG, /// then it is a loopback edge, so the corresponding edge from B' to S is left intact. /// b. If S is a loop header, but S appears after B in the reverse postorder sort of the CFG, /// then it is treated like other blocks (see c.) /// c. Otherwise, clone S to S', and rewrite B' to branch to S' instead of S. /// 4. Repeat step 2 for the successors of S, recursively, until the subgraph reachable from B /// /// Since we are treeifying blocks from the leaves of the CFG to the root, and because we do not /// follow loopback edges which escape/continue an outer loop - whenever we clone a subgraph of /// the CFG, we know that it has already been treeified, as we only start to treeify a block once /// all of the blocks reachable via that block have been treeified. /// /// In short, we're trying to split blocks with multiple predecessors such that all blocks have /// either zero or one predecessors, i.e. the CFG forms a tree. As mentioned previously, we must /// make an exception for loop headers, which by definition must have at least one predecessor /// which is a loopback edge, but this suits us just fine, as Miden Assembly provides control flow /// instructions compatible with lowering from such a CFG. /// /// # Examples /// /// ## Basic DAG /// /// This example demonstrates how the DAG of a function with multiple returns gets transformed: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 -> blk3 -> ret /// | / /// | / /// | / /// v v /// blk2 /// | /// v /// ret /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 -> blk3 -> ret /// | | /// | | /// | | /// v v /// blk2 blk2 /// | | /// v v /// ret ret /// ``` /// /// ## Basic Loop /// /// This is an example of a function with multiple returns and a simple loop: /// /// ```text,ignore /// blk0 /// | ------- /// v v | /// blk1 -> blk3 -> blk4 -> blk5 -> ret /// | / /// | / /// | / /// v v /// blk2 /// | /// v /// ret /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | ------- /// v v | /// blk1 -> blk3 -> blk4 -> blk5 -> ret /// | | /// | | /// | | /// v v /// blk2 blk2 /// | | /// v v /// ret ret /// ``` /// /// ## Complex Loop /// /// This is an example of a function with a complex loop (i.e. multiple exit points): /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <----- /// | | | /// | blk3 | /// | / \ | /// | / blk4-- /// | / | /// vv | /// blk5 blk6 /// ``` /// /// Becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | \ /// | blk2 <--- /// | | | /// | v | /// | blk3 | /// | | \ | /// | | blk4-- /// | | | /// v v v /// blk5 blk5 blk6 /// ``` /// /// NOTE: Here, when generating code for `blk5` and `blk6`, the loop depth is 0, so /// we will emit a single `push.0` at the end of both blocks which will terminate the /// containing loop, and then return from the function as we've reached the bottom /// of the tree. /// /// ## Nested Loops /// /// This is an extension of the example above, but with nested loops: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <------- /// | | | | /// | blk3 | | /// | / \ | | /// | / blk4-- | /// | / | | /// vv v | /// blk5<- blk6-->blk7-->blk8 /// | ^ | /// | |_____________| /// | | /// |__________________| /// ``` /// /// We have two loops, the outer one starting at `blk2`: /// /// * `blk2->blk3->blk4->blk2` /// * `blk2->blk3->blk4->blk6->blk7->blk2` /// /// And the inner one starting at `blk6`: /// /// * `blk6->blk7->blk8->blk6` /// /// Additionally, there are multiple exits through the loops, depending on the path taken: /// /// * `blk2->blk3->blk5` /// * `blk2->blk3->blk4->blk6->blk7->blk8->blk5` /// * `blk6->blk7->blk8->blk5` /// /// After transformation, this becomes: /// /// ```text,ignore /// blk0 /// | /// v /// blk1 /// | \ /// | blk2 <------- /// | | | | /// | blk3 | | /// | | \ | | /// | | blk4-- | /// | | | | /// v v v | /// blk5 blk5 blk6-->blk7-->blk8 /// ^ | | /// |_____________|_| /// | /// v /// blk5 /// ``` /// /// During codegen though, we end up with the following tree of stack machine code. /// /// At each point where control flow either continues a loop or leaves it, we must /// /// * Duplicate loop headers on control flow edges leading to those headers /// * Emit N `push.0` instructions on control flow edges exiting the function from a loop depth of N /// * Emit a combination of the above on control flow edges exiting an inner loop for an outer loop, /// depending on what depths the predecessor and successor blocks are at /// /// ```text,ignore /// blk0 /// blk1 /// if.true /// blk2 /// while.true /// blk3 /// if.true /// blk4 /// if.true /// blk2 # duplicated outer loop header /// else /// blk6 /// while.true /// blk7 /// if.true /// blk2 # duplicated outer loop header /// push.0 # break out of inner loop /// else /// blk8 /// if.true /// blk6 # duplicated inner loop header /// else /// blk5 /// push.0 # break out of outer loop /// push.0 # break out of inner loop /// end /// end /// end /// end /// else /// blk5 /// push.0 # break out of outer loop /// end /// end /// else /// blk5 /// end /// ``` #[derive(Default, PassInfo, ModuleRewritePassAdapter)] pub struct Treeify;

A rich, potentially multi-line description of this pass and its configuration. Read more
source§

impl RewritePass for Treeify

source§

type Entity = Function

The entity type to which this rewrite applies
source§

fn apply( &mut self, function: &mut Self::Entity, analyses: &mut AnalysisManager, session: &Session, ) -> RewriteResult

Apply this rewrite to entity
source§

fn should_apply(&self, _entity: &Self::Entity, _session: &Session) -> bool

Returns true if this rewrite should be applied to entity
source§

fn chain<R>(self, next: R) -> RewriteSet<Self::Entity>
where Self: Sized + 'static, R: RewritePass<Entity = Self::Entity> + 'static,

Apply this rewrite, then next as a pipeline of rewrites

Auto Trait Implementations§

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> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<D> OwoColorize for D

source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> Same for T

source§

type Output = T

Should always be Self
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.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<P> RewritePassInfo for P
where P: PassInfo + RewritePass,