Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Interactively Visualizing Ownership and Borrowing for Rust

License

NotificationsYou must be signed in to change notification settings

rustviz/rustviz

Repository files navigation

Build Status

RustViz is a tool that generates interactive visualizations from simple Rust programs to assist users in better understanding the RustLifetime and Borrowing mechanism.

RustViz is a project of theFuture of Programming Lab at the University of Michigan.

What does it look like?

RustViz generatesSVG files with graphical indicators that integrate withmdbook to render interactive visualizations of ownership and borrowing related events in a Rust program. Here's a sample view of what a visualization can look like:

alt tag

You can read more about it inour VL/HCC 2022 paper. Note that the section on generating visualizations is out of date, see below.

Usage

RustViz is capable of generating visualizations for simple Rust programs (albeit with certain limitations) that have been annotated by the user. We are not currently attempting to generate visualizations automatically. In this section, we'll showcase how to generate SVG renderings of examples provided by us.

RustViz requiresRust,Cargo andmdbook to be installed. Once you have installed all the above prerequisites, direct into/rustviz_mdbook and run the script:

~/rustviz/rustviz_mdbook$ ./view_examples.sh

You may have an output similar to this:

Generating visualizationsfor the following examples:building copy...building hatra1...building hatra2...building func_take_ownership...building func_take_return_ownership...2021-01-19 12:36:13 [INFO] (mdbook::book): Book building has started2021-01-19 12:36:13 [INFO] (mdbook::book): Running the html backendServing HTTP on :: port 8000 (http://[::]:8000/) ...

If you observed this output, then you have successfully generated the Rust visualization examples! Now open your browser and navigate tohttp://localhost:8000/. You should be able to view the examples individually by selecting them from the left side bar. To view the visualization, click the toggle button on the top right corner of the code block.

Great, this is how you can generate and view visualizations created usingRustViz. Now let's create one from scratch!

Step-By-Step Guide

In this section, we'll dive into creating an example,string_from_move_print. Note that all visualization examples are placed underrustviz/src/examples/ directory and you can create a new directory inrustviz/src/examples/ of your own.First, take note of the file structure we'll need to run the example:

string_from_move_print├── input│   └── annotated_source.rs└── source.rs

source.rs contains the untouched source code we wish to render into an image:

fnmain(){let x =String::from("hello");let y = x;println!("{}", y);}

In this example,String::from() moves a string ("hello") tox, thenx's resource is moved toy. Subsequently,println!() outputs a message toio::stdout without moving the resource.

annotated_source.rs contains style annotation tosource.rs so as to generate SVG for code panel.

fnmain(){let <tspan data-hash="1">x</tspan> = <tspan class="fn" data-hash="0" hash="3">String::from</tspan>("hello");let <tspan data-hash="2">y</tspan> = <tspan data-hash="1">x</tspan>;    <tspanpl-k">fn" data-hash="0" hash="4">println!</tspan>("{}", <tspan data-hash="2">y</tspan>);}

Next, let's familiarize ourselves with the syntax used inmain.rs. The RustViz tooldefines all possible owners, references or input of any memory resource as aResourceAccessPoint. In this case, we consider the functionString::from() and two variables,x andy, as Resource Access Points (RAPs). Each ofString::from() andx/y corresponds to RAPsResourceAccessPoint::Function andResourceAccessPoint::Owner, respectively.

Inmain.rs, we define these RAPs between theBEGIN andEND comments on lines 1 and 2:

/*--- BEGIN Variable Definitions ---Owner x; Owner y;Function String::from();--- END Variable Definitions ---*/

The definition header now can be automatically generated by running theview_examples.sh once. If any incorrect information appeared at the generated header, you could manully edit it by refering to the following documentation.

The format for eachResourceAccessPoint enum is shown below, where fields preceded by':' denote an optional field:

ResourceAccessPointUsage --Owner <:mut> <name>MutRef <:mut> <name>StaticRef <:mut> <name>Struct <:mut> <name>{<:mut> <member_1>, <:mut> <member_2>, ...}Function <name>

Alternatively, some codelet mut a = 5; andlet b = &a; would correspond toOwner mut a andStaticRef b, respectively.An immutable instance of some struct with member variablesx andmut y, on the other hand, may be annotated asStruct a{x, mut y}.

It is important to note:

  1. all definitionsmust lie betweenBEGIN andEND
  2. all definitionsmust be defined in the same order by which they were declared in the source code
  3. all definitionsmust be separated by a singular semicolon
  4. each field within a RAP definitionmust be separated by a whitespace

After running theview_examples.sh once we should have the following file structure:

string_from_move_print├── input│   └── annotated_source.rs├── main.rs└── source.rs

Next, we annotate the code with the use ofExternalEvents thatdescribe move, borrow, and drop semantics of Rust. Instring_from_move_print, we have four such events:

  1. Move of resource fromString::from() tox
  2. Move of resource fromy tox
  3. Drop of resource binded tox
  4. Drop of resource binded toy

We can specify Events in structured comments like so:

/* --- BEGIN Variable Definitions ---Owner x; Owner y;Function String::from(); --- END Variable Definitions --- */fnmain(){let x =String::from("hello");// !{ Move(String::from()->x) }let y = x;// !{ Move(x->y) }println!("{}", y);// print to stdout!}/* !{    GoOutOfScope(x),    GoOutOfScope(y)} */

Each Event is defined on the line where it occurs and within delimiters!{ and}.

Events can be annotated within block comments; however, the blockmust start on the line in which the events occur. Additionally, all Events within a!{} delimitationmust be separated by a singular comma and must each follow the format:

ExternalEventsUsage:Format: <event_name>(<from>-><to>)        e.g.:// !{ PassByMutableReference(a->Some_Function()), ... }Note:GoOutOfScope andInitRefParam require onlythe <from> parameter        e.g.:// !{ GoOutOfScope(x) }

Refer to theAppendix for a list of usableExternalEvent's.

Phew! All that's left is running the program. Simply navigate intosrc and run:

cargo run string_from_move_print

Now your folder should look like this:

string_from_move_print├── input│   └── annotated_source.rs├── main.rs├── source.rs├── vis_code.svg└── vis_timeline.svg

Congratulations! You have successfully generated your first visualization! As a last step, add the name of your example totargetExamples underview_examples.sh and run the script fromrustviz_mdbook to see it in your browser.

Appendix

ExternalEvent Usage:

EventUsage
Bind(a)Let binding or assignment.
e.g.:let a = 1;
Copy(a->b)Copies the resource ofa to variableb. Here,a implements theCopy trait.
Move(a->b)Moves the resource ofa to variableb. Here,a implements theMove trait.
Note: Moving toNone (i.e.:Move(a->None)) is used to express a move to the caller function.
StaticBorrow(a->b)Assigns an immutable reference ofa tob.
e.g.:let b = &a;
MutableBorrow(a->b)Assigns a mutable reference ofa tob.
e.g.:let b = &mut a;
StaticDie(a->b)Ends the non-lexical lifetime of the reference variablea and returns the resource back to its ownerb.
MutableDie(a->b)Ends the non-lexical lifetime of the reference variablea and returns the resource back to its ownerb.
PassByStaticReference(a->b)Passes an immutable reference of variablea to functionb. Not to be confused with StaticBorrow.
PassByMutableReference(a->b)Passes a mutable reference of variablea to functionb. Not to be confused with MutableBorrow.
GoOutOfScope(a)Ends the lexical lifetime of variablea.
InitRefParam(a)Initializes the parametera of some function, which is a reference.
e.g.:some_fn(a: &String) {..}
InitOwnerParam(a)Initializes the parametera of some function, which owns the resource.
e.g.:some_fn(a: String) {..}

Note:

  1. GoOutOfScope,InitRefParam andInitOwnerParam require a singular parameter previously defined in theVariable Definitions section.(e.g.:// !{ GoOutOfScope(x) })
  2. All other events require two parameters,a andb, which can either be defined (e.g.:Owner a) or undefined (None).

TheNone type can be used as the<to> parameter (e.g.:Move(a->None)) to specify a move to the function caller.

  1. All uses ofStruct fields must be preceded by its parent struct's name. (e.g.:a.b = 1; can be annotated asMove(None->a.b), wherea is the parent andb is the field.)

Visualization Limitations

Some features are still being built. As of now, we are limited to:

  • No branching logic
  • No looping
  • No explicit lifetime annotation

About

Interactively Visualizing Ownership and Borrowing for Rust

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors12


[8]ページ先頭

©2009-2025 Movatter.jp