Skip to content

Instantly share code, notes, and snippets.

@davidsirr
Last active June 16, 2021 09:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidsirr/c5730d8b2fde64f2365f3b05e8d3eced to your computer and use it in GitHub Desktop.
Save davidsirr/c5730d8b2fde64f2365f3b05e8d3eced to your computer and use it in GitHub Desktop.
setup rust dev on OSX

Setup Rust Dev environment on Mac OSX

Just a reminder on how I setup my machine for Rust dev

Install the Rust binaries

Install Homebrew Package Manager

Homebrew (Mac)

https://brew.sh/

Install rustup, rust toolchain manager

in terminal

    brew install rustup

Initialise the Rust Env

in terminal

    rustup-init

choose default option: 1 at prompt

now restart terminal to get new path picked up

Test install of rust binaries

in terminal

    rustc

should return bunch of rustc command doco

scaffold a test rust project

in terminal

    ~/Code/$ cargo new myProject

Setup VSCode

open vscode (assuming you setup the "code" terminal shortcut

    ~/Code/myProject/$ code .

save vscode workspace for the project

Install some Rust language Extensions

CMD+SHIFT+P

select: Extensions: install extensions

Install the following:

  • Rust (basic language support)
  • Tabnine (additional intellisense)

Using Tasks

In the root of your project (containing the Cargo.toml file) create a folder called .vscode. Inside .vscode, create a file called tasks.json and place the content of this gist inside the json file.

Then press CMD+SHIFT+B or F5 when your main.rs is open.

Referring to https://code.visualstudio.com/docs/editor/tasks#vscode in order to setup tasks create .vscode/tasks.json file and populate with text below providing build and run task.

    // Available variables which can be used inside of strings.
    // ${workspaceRoot}: the root folder of the team
    // ${file}: the current opened file
    // ${fileBasename}: the current opened file's basename
    // ${fileDirname}: the current opened file's dirname
    // ${fileExtname}: the current opened file's extension
    // ${cwd}: the current working directory of the spawned process
    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "build",
          "args": ["build", "-v"],
          "command": "cargo",
          "group": "build",
          "problemMatcher": [
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "pattern": {
                "regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
                "file": 1,
                "line": 2,
                "column": 3,
                "endLine": 4,
                "endColumn": 5,
                "severity": 6,
                "message": 7
              }
            }
          ]
        },
        {
          "label": "clean",
          "args": ["clean"],
          "presentation": {
            "reveal": "always"
          }
        },
        {
          "label": "run",
          "args": ["run", "-v"],
          "presentation": {
            "reveal": "always"
          },
          "group": "build",
          "problemMatcher": [
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "pattern": {
                "regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
                "file": 1,
                "line": 2,
                "column": 3,
                "endLine": 4,
                "endColumn": 5,
                "severity": 6,
                "message": 7
              }
            }
          ]
        },
        {
          "label": "test",
          "args": ["test"],
          "presentation": {
            "reveal": "always"
          },
          "group": "test",
          "problemMatcher": [
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "pattern": {
                "regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
                "file": 1,
                "line": 2,
                "column": 3,
                "endLine": 4,
                "endColumn": 5,
                "severity": 6,
                "message": 7
              }
            },
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "severity": "error",
              "pattern": {
                "regexp": "^.*panicked\\s+at\\s+'(.*)',\\s+(.*):(\\d+)$",
                "message": 1,
                "file": 2,
                "line": 3
              }
            }
          ]
        },
        {
          "label": "bench",
          "args": ["bench"],
          "presentation": {
            "reveal": "always"
          },
          "group": "test",
          "problemMatcher": [
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "pattern": {
                "regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
                "file": 1,
                "line": 2,
                "column": 3,
                "endLine": 4,
                "endColumn": 5,
                "severity": 6,
                "message": 7
              }
            },
            {
              "owner": "rust",
              "fileLocation": ["relative", "${workspaceRoot}"],
              "severity": "error",
              "pattern": {
                "regexp": "^.*panicked\\s+at\\s+'(.*)',\\s+(.*):(\\d+)$",
                "message": 1,
                "file": 2,
                "line": 3
              }
            }
          ]
        }
      ]
    }

setup debugger

Installing extension

If CodeLLDB (A native debugger extension for VS Code) is not already installed then install the extension via Open command palette using Command+p as (or Control+p) as above and enter

    ext install vadimcn.vscode-lldb and enter.

On a MAC press function F5 or via menu using Run -> Start Debugging and select LLDB option. VS Code will display a message stating Cannot start debugging because no launch configuration has been provided. Select default options in order to generate a launch file.

Open src/main.rs and place breakpoint to left of the line number 3 println!(“Hello, world!”)and press F5 or Run -> Start Debugging to start the debugger.

David's notes on Rust

compile a script: rustc file.rs then run binary as ./file

! indicates a macro ; end of line

print complex objects to console: println!("{:?}", array);

cargo package manager

cargo new hello_cargo --bin - creates a "toml" file - creates a src folder

cargo debug -- compile debug cargo run -- compile and run cargo check < no build, validate

all variables immutable by default; need to declare with mut to allow changing "mutable"

Rust is a statically typed language

Data Types

  • scalar > a single value

    • integer; default to i32; can assign 64bit with type annotation let x:i64 = 43542354;
    • float: f32 and f64 annotation options
    • boolean: let f = true; or let f:bool = true
    • characters: char type: unicode scalar value; let c = 'z'; SINGLE QUOTES string type: later...
  • compound

    • tuples
      • group a variety of types
      • think struct or dictionary
      • declaring: let tup: (i32, f64, u8) = (500, 2.4, 1);
      • destructuring: let (x, y, z) = tup; println!("X= {}, Y= {}, Z={}", x, y, z);
      • access by position: let a = tup.0; let b = tup.1;
    • arrays
      • collection of the SAME variable type
      • arrays in rust are fix length! cant resize
      • iteration: for element in months.iter() {
  • functions

    • main is the default function
    • snake case lower case with underscores for naming
    • return type indicated after the ->: fn sum(x:i32, y:i32) -> i32 {
    • implicit return function is the final statement of the function WITHOUT SEMICOLON! fn sum(x:i32, y:i32) -> i32 { x + y }
    • you can use an explicit return command
  • control flow

    • if - standard
    • loops
      • loop { break; }
      • while x != y, etc
      • for element in arrayVar.iter() loop
  • memory management in rust

    • stack - stores values by order created in LIFO; data always appends, data lengths must be known, fixed and fast

      • integers, booleans and literal strings (str) go here (Since the size of literals are fixed, they can be stored on the stack in a sequential manner.)
    • heap - unorganised, variable lengths, requires memory pointers

      • compound/complex types go here, inc complex strings (String::from("hello"))
      • Note: metadata for these variables are stored on the stack
    • rust has no garbage collector

    • rust uses concept of OWNERSHIP

    • rust calls drop to remove the variable from memory automatically when the var goes out of scope

    • the variable is the owner of the value

    • variables exist within scopes

    • each value can only be owned by one assignment at a time

    • when it exits the scope the value is destroyed

    • string types are memory allocated on the heap at run time

    • :: is used to advanced create function

    • let mut s = String::from("Hello"); < "Hello" is the initial value which allocates the first memory space

      • s.push_str(", world!"); < appends by creating a new memory space
    • when out of scope it will invalidate the variable and remove it

    • for non simple data types (incl string), there are no default variable assignments by reference in rust! there is a shallow copy done.

      • the first variable is dereferenced and no longer exists!!
    • let s2 = s1 < makes s1 no longer exist; the value in s1 MOVES to s2

    • if you pass s2 into a function as an argument it is then dereferenced in current scope!

      • let s2 = 'foo'; func(s2); println!({},s2) < fails!
    • for complex types, you need to use explicit REFERENCES with "&" prepending the variable send and input

      • this is a BORROW, allows to use a variable without taking ownership (assign by reference!)

      let s = String::from("hello"); // s comes into scope. function_call(&s); fn_function_call(input_string: &String) { println!("{}",input_string); } println!("{}",s); < this now works!

      • if you want to allow changing the value, you must append mut to all passes
      • NOTE you can only have one mutation of a variable in a given scope

      let mut s = String::from("hello"); // s comes into scope. function_call(&mut s); fn_function_call(input_string: &mut String) { println!("{}",input_string); } println!("{}",s); < this now works!

    • simple variables like int will be passed via COPY! beware

    • NOTE if you pass numeric by reference and want to mutate, you need to reference the variable with *!!! e.g. fn makes_copy(some_integer: &mut i32) { // some_integer comes into scope. *some_integer = *some_integer + 1;

    • race conditions

      • remember! variables will be gone after the scope is complete (just good scoping practice...)
    • array or string slice

      • slices is a range of values from the heap from the variable
      • let s = String::from("hello"); slice = &s[0..3] > results in: "hel
    • struct is like class, creating a new data type, similar to tuples

      • unlike tuples you name the variables and define the types struct Rectangle{ width: u32, height: u32, }

      • structs can act like a class with methods

        • stuct methods always have parameter of &self

        impl Rectangle{ fn area(&self) -> u32{ self.width * self.height
        } }

    • enumerations

      • like a struct but allows storage of types

      • only assigns ONE of the attributes, unlike a struct

      • can impl enums with methods

      • allows complex types

      • create a new type with possible values fn main() { enum IpAddressType { V4(String), V6(String) }

          let home = IpAddressType::V4(String::from("127.0.0.1"));
          let loopback = IpAddressType::V6(String::from("::1"));
        

        }

      • allows you to use strong typing to allow the enum root type "IpAddressType" only but then switch on the enumeration within

    • pattern matching

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment