Writing Crates for Complete Beginners: A Tour of Turtle

 

By Sunjay Varma

twitter.com/sunjay03

github.com/sunjay

RustConf 2018

Talk Outline

  • The Turtle Crate
  • How does turtle work?
  • Designing a crate for complete beginners

@sunjay03

Rust Resources

@sunjay03

Online Tutorials/Websites

Even more resources listed here:

github.com/ctjhoa/rust-learning

@sunjay03

My goal with turtle is to create the resources and community we need in order to make Rust a language that anyone can learn.

The Turtle Crate

@sunjay03

@sunjay03

Pen

Turtle Legs?

Turtle Shell

Turtle

@sunjay03

@sunjay03

Source code for these images can be found in the examples/ directory in the turtle GitHub repo

Methods on the Turtle struct

Movement & Rotation:

  • turtle.forward
  • turtle.backward
  • turtle.right
  • turtle.left

Speed, Position, & Heading:

  • turtle.set_speed
  • turtle.go_to
  • turtle.set_heading
  • turtle.turn_towards

Pen Control:

  • turtle.set_pen_size
  • turtle.set_pen_color
  • turtle.pen_down
  • turtle.pen_up

Shape Filling & Turtle Visibility:

  • turtle.begin_fill
  • turtle.end_fill
  • turtle.hide
  • turtle.show

See the complete list in the documentation: docs.rs/turtle

@sunjay03

Turtle Graphics

TO Square
  REPEAT 4 [ FD 100 RT 90 ]
END

TO Flower
  SETPC [255 000 255] SETPENSIZE [4 4]
  CS HT REPEAT 36 [ PU FD 4 PD Square LT 10 ] 
  SETPENCOLOR [0 0 0] SETPENSIZE [1 1] PU HOME PD 
END

Flower

The Turtle Robot

The Logo Programming Language

@sunjay03

Fun fact: My mom introduced me to Logo when I was 12 and I used it to draw a lot of pretty neat pictures back in the day.

The Python turtle Module

The Rust turtle Crate

import turtle

for i in xrange(4):
    turtle.forward(200)
    turtle.right(90)

extern crate turtle;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}

Modifies "global mutable state" in the turtle module

Creates a new turtle explicitly

The "mut" on the variable above lets us modify the position and rotation of the turtle here

@sunjay03

Tells you exactly how to fix the error

How does turtle work?

Image from: examples/heart.rs in turtle GitHub repo

@sunjay03

extern crate turtle;

use turtle::{Turtle, Color};

fn main() {
    let mut turtle = Turtle::new();

    turtle.drawing_mut().set_background_color("#112244");
    turtle.wait_for_click();

    turtle.pen_up();
    turtle.backward(160.0);
    turtle.right(90.);
    turtle.forward(110.);
    turtle.pen_down();
    turtle.set_speed("faster");

    dragon(&mut turtle, -90., 11, 0., 255.);

    turtle.hide();
}

/// Draw the dragon curve by simulating folding a strip of paper
fn dragon(
    turtle: &mut Turtle, 
    fold_direction: f64, 
    num_folds: usize, 
    color_start: f64, 
    color_end: f64
) {
    let color_mid = (color_start + color_end) * 0.5;
    if num_folds == 0 {
        // mapping a color number 0-255 to an rgb gradient.
        turtle.set_pen_color(Color {
            red: ((color_mid - 128.).abs() * 2.).floor(),
            green: color_mid,
            blue: 160.,
            alpha: 1.,
        });
        return turtle.forward(10.);
    }

    // draw a left to right strip (which has a left turn in the middle)
    dragon(turtle, -90., num_folds - 1, color_start, color_mid);
    turtle.right(fold_direction);
    // draw a right to left strip (which has a right turn in the middle)
    dragon(turtle, 90., num_folds - 1, color_mid, color_end);
}

This code only gives instructions to the turtle and ignores the window, events, etc.

There is no event loop, window management, or rendering code here.

Code from examples/dragon.rs in turtle GitHub repo

Contributed by @exoticorn

@sunjay03

An Event Loop

"Manish asked himself: Is that an event loop?"

User interacts with your application

Application renders your drawings on the screen...

Event loop quickly switches back and forth between these

...and runs your program as fast as possible

Hmm...

*click*

*type*

*click*

Wow! Sunjay is SO cool!

@sunjay03

Attempt #1: Multithreaded

User's Program

main thread

extern crate turtle;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}

Turtle Event Loop

background thread

spawns new thread

waits for the window to be closed before ending the main thread

opens window

starts drawing & handling events

sends drawing command messages

@sunjay03

share state without blocking each other for too long

@sunjay03

extern crate turtle;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}
extern crate turtle;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    let mut i = 0;
    while turtle.is_window_open() {
        turtle.render();

        if i < 4 {
            turtle.forward(200.0);
            turtle.right(90.0);
            i += 1;
        }
    }
}

Before

After

manually managing the event loop

@sunjay03

Attempt #2: Multiprocessing

User's Program

main thread

extern crate turtle;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    for _ in 0..4 {
        turtle.forward(200.0);
        turtle.right(90.0);
    }
}

Turtle Event Loop

background thread

opens window

starts drawing & handling events

@sunjay03

spawns new thread

waits for the window to be closed before ending the main thread

sends drawing command messages

share state without blocking each other for too long

process

process

between processes

keep state in sync between both processes

main thread #2

#1

#1

The PR that saved the day: github.com/sunjay/turtle/pull/31

@sunjay03

@sunjay03

@sunjay03

@sunjay03

@sunjay03

Big Plans For The Future!

  • Multiple turtles
  • 3D drawing
  • Text rendering support
  • Buttons and text fields for input
  • Asynchronous turtles using async/await/Future
  • Web assembly support
  • and much, much more!

@sunjay03

Try out turtle today!

Image from examples/maze in turtle GitHub repo

@sunjay03

Designing a crate for complete beginners

Tips to make your crates accessible to a wider audience

@sunjay03

Docs · Audience · Examples · Guide

Design for the audience that makes sense for your crate

.

 

 

 

.

Level of experience

You don't need to be doing this...

.

 

 

 

.

Level of experience

.

 

 

 

.

Level of experience

...in order to do this

.

 

 

 

.

Level of experience

@sunjay03

@sunjay03

cargo test

Runs all of the tests in a Rust project

--features test

Required by turtle to avoid lots of problems

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

Good Documentation

@sunjay03

  • Writing documentation that is actually good takes some thought
     
  • Think about the person using your documentation
     
  • What do they already know? What do I need to explain to them so that they understand what they need to do?
     
  • Make sure they get the most important information first
     
  • Write most of your documentation as you write code so you don't forget what you need to write down

Good Documentation

@sunjay03

Good Documentation

@sunjay03

Good Documentation

Links to websites that explain concepts so that we don't have to explain them ourselves

@sunjay03

Good Documentation

Help people get around your documentation quickly

@sunjay03

Examples

@sunjay03

Examples

@sunjay03

Examples

@sunjay03

For demonstrating a specific method:

For full examples of using your crate:

cargo run --example circle

These examples are tested automatically

A Guide

@sunjay03

The Rust API Guidelines

@sunjay03

Read the full guidelines here:

rust-lang-nursery.github.io/api-guidelines

Thank you!

Please go try turtle out!

github.com/sunjay/turtle

@sunjay03

Thank you everyone who contributes code and everyone who opens issues!

@sunjay03

Thank you!

Made with Slides.com