C:\github\JimFawcett\RustStory\Chap_1_Models
> cargo new hello_world
Creating binary (application) `hello_world` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
C:\github\JimFawcett\RustStory\Chap_1_Models
> cd hello_world
C:\github\JimFawcett\RustStory\Chap_1_Models\hello_world
> dir
Directory: C:\github\JimFawcett\RustStory\Chap_1_Models\hello_world
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/22/2024 12:13 PM src
-a---- 8/22/2024 12:13 PM 82 Cargo.toml
C:\github\JimFawcett\RustStory\Chap_1_Models\hello_world
>
fn main() {
println!("Hello, world!");
}
> cargo run
Compiling hello_world v0.1.0 (C:\github\JimFawcett\RustStory\Chap_1_Models\hello_world)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
Running `target\debug\hello_world.exe`
Hello, world!
[package]
name = "hello"
version = "0.1.0"
authors = ["James W. Fawcett "]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
Link | Description |
---|---|
Considering Rust - Feb 2020 - Jon Gjengset | Great what-is-it video, with code snippets and a lot of mind setting conversation by a very knowledgeable presenter. |
RustModels.pdf | Discussion of principle ideas on which Rust is based. |
Rust std | Very clear documentation for the Rust std facilities, e.g., types, modules, macros, and keywords. |
A half-hour to learn Rust | Code fragments with commentary that cover most of the Rust ideas. |
Rust Cheat Sheet | Very broad reference to the Rust language, its libraries, and idioms. |
Rust Containers | Container diagrams |
Diving into Rust |
Contains an excellent video you |
Rust Basic Code Demos | Small code examples that probe how Rust functions |
Places to visit later | Description |
Shared reference &T and exclusive reference &mut T | More accurate description than immutable reference and mutable reference |
Elegant APIs in Rust | Things to consider when writing Rust functions and packages |
Soundness Pledge | Commentary about Rust programming goals and ideals - how not to subvert safety goals. |
mod helper; // declares helper module
use helper::{ say };
use demo_lib::{ libsay };
fn main() {
helper::say();
say();
demo_lib::libsay();
libsay();
print!("\n Hello, world!\n\n");
}
pub fn say() {
print!("\n hello from helper");
}
pub fn libsay() {
print!("\n hello from demo_lib");
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
cargo -q run
hello from helper
hello from helper
hello from demo_lib
hello from demo_lib
Hello, world!
[package]
name = "demo"
version = "0.1.0"
authors = ["James W. Fawcett <jfawcett@twcny.rr.com>"]
edition = "2018"
[dependencies]
demo_lib = { path = "../demo_lib" }
/////////////////////////////////////////////////////////////
// display::lib.rs - Demonstrate display types //
// //
// Jim Fawcett, https://JimFawcett.github.io, 25 Mar 2020 //
/////////////////////////////////////////////////////////////
/*
log and do_work are derived from:
https://doc.rust-lang.org/beta/std/any/index.html
*/
use std::any::type_name;
use std::any::Any;
use std::fmt::Debug;
use std::mem::size_of;
/*-----------------------------------------------
Accepts either String or str
- no automatic newline
*/
pub fn shows<S: Into<String>>(s: S) {
print!("{}", s.into());
}
/*-------------------------------------------------------------
Display message and value
- no automatic newline
*/
pub fn show<T: Debug>(msg: &str, t: &T) {
print!("{}{:?}", msg, t);
}
pub fn str_show<T: Debug>(msg: &str, t: &T) -> String {
format!("{}{:?}", msg, t)
}
/*-------------------------------------------------------------
show value
- expects T to implement Debug
*/
pub fn show_value<T: Debug>(value: &T) {
print!("\n value: {:?}", value);
}
pub fn str_show_value<T: Debug>(value: &T) -> String {
format!("\n value: {:?}", value)
}
/*-------------------------------------------------------------
show type name
*/
pub fn show_type<T>(_value: &T) {
let name = std::any::type_name::<T>();
print!("\n TypeId: {}, size: {}", name, size_of::<T>());
}
pub fn str_show_type<T>(_value: &T) -> String {
let name = std::any::type_name::<T>();
format!("\n TypeId: {}, size: {}", name, size_of::<T>())
}
/*-------------------------------------------------------------
show type name and value
- expects T to implement Debug
- see #[define(Debug)] attributes, above
*/
pub fn log<T: Debug>(value: &T) {
let name = type_name::<T>();
print!("\n TypeId: {}, size: {}", name, size_of::<T>());
print!("\n value: {:?}", value);
}
pub fn str_log<T: Debug>(value: &T) -> String {
let name = type_name::<T>();
let mut st = format!("\n TypeId: {}, size: {}", name, size_of::<T>());
let st1 = format!("\n value: {:?}", value);
st.push_str(&st1);
st.clone()
}
/*-------------------------------------------------------------
log type name and value
- expects T to implement Debug
This function is deprecated. Its here to avoid breaking
older code.
*/
pub fn slog<T: Any + Debug>(value: &T) {
let value_any = value as &dyn Any;
let name = type_name::<T>();
print!("\n TypeId: {}, size: {}", name, size_of::<T>());
// Try to convert our value to a `String`. If successful, we want to
// output the String`'s length as well as its value. If not, it's a
// different type: just print it out unadorned.
match value_any.downcast_ref::<String>() {
Some(as_string) => {
print!("\n value: String ({}): {}", as_string.len(), as_string);
}
None => {
print!("\n value: {:?}", value);
}
}
}
/*-------------------------------------------------------------
Display underlined main title on console
*/
pub fn main_title(msg: &str) {
print!("\n {}", msg);
let s = "=".repeat(msg.len() + 2);
print!("\n {}", s);
}
/*-------------------------------------------------------------
Display underlined sub title on console
*/
pub fn sub_title(msg: &str) {
print!("\n {}", msg);
let s = "-".repeat(msg.len() + 2);
print!("\n {}", s);
}
/*-------------------------------------------------------------
show line with len hyphens
*/
pub fn separator(len: u8) {
let mut s = String::new();
for _i in 1..len + 2 {
s.push('-');
}
print!("\n {}", s);
}
/*-------------------------------------------------------------
push a single newline to console
*/
pub fn putline() {
println!();
}
/*-------------------------------------------------------------
pust n newlines to console
*/
pub fn putlinen(n: usize) {
let s = "\n".repeat(n);
print!("{}", s);
}
///////////////////////////////////////////////////////////////
// display::main.rs tests - Demonstrate display types //
// //
// Jim Fawcett, https://JimFawcett.github.io, 25 Mar 2020 //
///////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
#[allow(dead_code)]
struct Point {
x: f64,
y: f64,
z: f64,
}
#[test]
/*
Library doesn't write to console, so all this tests is that
no panic occurred. See test_display for useful tests.
*/
fn test_show_type() {
let mut str = String::new();
str.push_str("a string");
assert_eq!(str_show_type(&str).contains("TypeId:"), true);
}
#[test]
fn test_show_value() {
let mut str = String::new();
str.push_str("a string");
assert_eq!(str_show_value(&str).contains("value:"), true);
}
#[test]
fn test_log() {
let an_i8: i8 = 100;
assert_eq!(str_log(&an_i8).contains("100"), true);
let mut vi: Vec<i32> = Vec::new();
vi.push(-1);
vi.push(0);
vi.push(1);
assert_eq!(str_log(&vi).contains("1]"), true);
#[derive(Debug)]
enum Test {
Test1,
Test2,
}
log(&Test::Test1);
log(&Test::Test2);
let point = Point {
x: 1.0,
y: 1.5,
z: 2.0,
};
log(&point);
assert_eq!(str_log(&point).contains("2.0 }"), true);
sub_title("that's all folks!");
}
}
/* run using: cargo --example demo_displays */
extern crate display;
use display::*;
#[allow(dead_code)] /*-- fields are not explicitly read -*/
#[derive(Debug)]
pub struct Point {
x: f64,
y: f64,
z: f64,
}
fn test_displays() {
main_title("demo display");
sub_title("-- shows --");
putline();
sub_title("-- show_type and show_value --");
let mut str = String::new();
str.push_str("a string");
show_type(&str);
show_value(&str);
putline();
sub_title("-- log --");
let an_i8: i8 = 100;
log(&an_i8);
let mut vi: Vec<i32> = Vec::new();
vi.push(-1);
vi.push(0);
vi.push(1);
log(&vi);
#[derive(Debug)]
enum Test {
Test1,
Test2,
}
log(&Test::Test1);
log(&Test::Test2);
let point = Point {
x: 1.0,
y: 1.5,
z: 2.0,
};
log(&point);
print!("\n {:?}", point);
putline();
sub_title("-- show --");
show("\n this is a Point structure\n ", &point);
putline();
sub_title("that's all folks!");
putline();
}
fn main() {
test_displays();
}
demo display
==============
-- shows --
---------------
-- show_type and show_value --
----------------------------------
TypeId: alloc::string::String, size: 24
value: "a string"
-- log --
-------------
TypeId: i8, size: 1
value: 100
TypeId: alloc::vec::Vec<i32>, size: 24
value: [-1, 0, 1]
TypeId: demo_display::test_displays::Test, size: 1
value: Test1
TypeId: demo_display::test_displays::Test, size: 1
value: Test2
TypeId: demo_display::Point, size: 24
value: Point { x: 1.0, y: 1.5, z: 2.0 }
Point { x: 1.0, y: 1.5, z: 2.0 }
-- show --
-------------
this is a Point structure
Point { x: 1.0, y: 1.5, z: 2.0 }
that's all folks!
-------------------
let i = 3; // i is blittable
let mut j = i; // j gets copy of i
print!("\n i = {}, j = {}", i, j);
// i is still usable
let s = String::from("String named s"); // s is not blitable
let mut t = s; // s is moved to t
t.push_str(" with more stuff");
print!("\n t = {}", t);
// statement below will fail to compile
// print!("\n s = {}", s); // can't use s, been moved
i = 3, j = 3
t = String named s with more stuff
let i = 3;
let mut j = i; // copy of i
let r = &mut j; // mutable ref to j
*r += 2; // mutating j thru r
///////////////////////////////////////////////////////
// won't compile:
// print!("\n i = {}, j = {}, r = {}", i, j, r);
// print! takes its arguments by reference
// so can't pass r, as that would make a second
// reference where the first is mutable - not allowed
let z = *r; // copy r's referent value
print!("\n i = {}, j = {}, z = {}", i, j, z);
i = 3, j = 5, z = 5
Ownership Details | |
---|---|
RustModels.pdf RustModels code demos |
Discussion of RwLock ownership, Copies, Moves, Clones, reference borrowing, mutability with code examples |
RustBasicDemos.html | Large collection of demos, several for ownership |
/*-- fully specified --*/
let i:i32 = 5;
let f:f64 = 3.4;
let a:[f32; 5] = [1.0, 1.5, 2.0, 1.5, 1.0];
let t:(i32, f64, String) = (1, 2.0, "three".to_string());
#[derive(Debug)]
struct S<'a>{i:i32, s:&'a str, };
let s:S = S{i:15, s:"a literal string" };
#[derive(Debug)]
enum E {BS(String), MS(String), PhD(String),};
let e:E = E::MS("Computer Engineering".to_string());
print!("\n -- fully specified types --\n");
print!("\n i = {:?}", i);
print!("\n f = {:?}", f);
print!("\n a = {:?}", a);
print!("\n t = {:?}", t);
print!("\n s = {:?}", s);
print!("\n e = {:?}", e);
/*-- using type deduction --*/
let i = 5;
let f = 3.4;
let a = [1.0, 1.5, 2.0, 1.5, 1.0];
let t = (1, 2.0, "three".to_string());
let s = S{i:15, s:"a literal string" };
let e = E::MS("Computer Engineering".to_string());
print!("\n\n -- using type deduction --\n");
print!("\n i = {:?}", i);
print!("\n f = {:?}", f);
print!("\n a = {:?}", a);
print!("\n t = {:?}", t);
print!("\n s = {:?}", s);
print!("\n e = {:?}", e);
-- fully specified types --
i = 5
f = 3.4
a = [1.0, 1.5, 2.0, 1.5, 1.0]
t = (1, 2.0, "three")
s = S { i: 15, s: "a literal string" }
e = MS("Computer Engineering")
-- using type deduction --
i = 5
f = 3.4
a = [1.0, 1.5, 2.0, 1.5, 1.0]
t = (1, 2.0, "three")
s = S { i: 15, s: "a literal string" }
e = MS("Computer Engineering")
/////////////////////////////////////////////////////////////
// probe_traits.rs - demo user defined traits //
// //
// Jim Fawcett, https://JimFawcett.github.io, 22 Mar 2020 //
/////////////////////////////////////////////////////////////
use std::fmt::{Debug};
use display::{*};
/*-----------------------------------------------
Note that all trait functions are public
*/
/*-----------------------------------------------
Show trait needs Super trait Debug
- provides default method implementation
*/
trait Show : Debug {
fn show(&self) {
print!("\n {:?}", &self);
}
}
/*-----------------------------------------------
Stucts that use Size must implement fn size
- no default impl provided
*/
trait Size {
fn size(&self) -> usize;
}
#[derive(Debug, Copy, Clone)]
pub struct Test { // public type
x:i32, y:f64, // private data
}
/*-----------------------------------------------
Implementing traits
*/
impl Show for Test {} // using default impl
impl Size for Test { // must provide impl
fn size(&self) -> usize {
std::mem::size_of::<Test>()
}
}
/*-----------------------------------------------
Implementing methods
*/
impl Test {
pub fn new() -> Self {
Self {
x:42,
y:1.5,
}
}
pub fn get_x(&self) -> i32 {
self.x
}
pub fn set_x(&mut self, v:i32) {
self.x = v;
}
pub fn get_y(&self) -> f64 {
self.y
}
pub fn set_y(&mut self, v:f64) {
self.y = v;
}
}
#[allow(dead_code)]
pub fn run () {
main_title("Demonstrating probe_traits");
putline();
sub_title("using Show trait");
let mut t = Test::new();
t.show();
putline();
sub_title("using getters and setters");
t.set_x(3);
t.set_y(-3.5);
print!("\n x = {}, y = {}", t.get_x(), t.get_y());
putline();
sub_title("using Size trait");
print!("\n size = Test instance t = {}", t.size());
/*-------------------------------------------
Implementing Size for built in types!
*/
impl Size for i32 {
fn size(&self) -> usize {
std::mem::size_of::<i32>() as usize
}
}
impl Size for f64 {
fn size(&self) -> usize {
std::mem::size_of::<f64>() as usize
}
}
let sx = t.x.size();
let sy = t.y.size();
print!("\n size of x = {}, size of y = {}", sx, sy);
print!("\n remaining 4 bytes is padding for alignment");
putline();
sub_title("exploring struct layout with safe pointers");
let mut t = Test::new();
t.show();
shows("\n Note: Test implements traits:");
shows("\n Show, Size, Debug, Copy, Clone");
shows("\n Missing 4 bytes is padding for alignment.\n");
let rt = &t as *const Test;
let rx = &t.x as *const i32;
let ry = &mut t.y as *mut f64;
let st = std::mem::size_of::<Test>();
let sx = std::mem::size_of::<i32>();
let sy = std::mem::size_of::<f64>();
print!("\n address of t = {:?}", rt as i32);
print!("\n address of t.x = {:?}", rx as i32);
print!("\n address of t.y = {:?}", ry as i32);
print!("\n size of t = {:?}", st);
print!("\n size of x = {:?}", sx);
print!("\n size of y = {:?}", sy);
print!("\n address of t + st = {:?}", rt as i32 + st as i32);
putline();
}
demo display
==============
-- shows --
---------------
-- show_type and show_value --
----------------------------------
TypeId: alloc::string::String, size: 24
value: "a string"
-- log --
-------------
TypeId: i8, size: 1
value: 100
TypeId: alloc::vec::Vec, size: 24
value: [-1, 0, 1]
TypeId: demo_display::test_displays::Test, size: 1
value: Test1
TypeId: demo_display::test_displays::Test, size: 1
value: Test2
TypeId: demo_display::Point, size: 24
value: Point { x: 1.0, y: 1.5, z: 2.0 }
Point { x: 1.0, y: 1.5, z: 2.0 }
-- show --
-------------
this is a Point structure
Point { x: 1.0, y: 1.5, z: 2.0 }
that's all folks!
-------------------
Table 1. Test Struct Memory Layout | ||
---|---|---|
Component | Address | Size - bytes |
Test Struct | 8190584 | 16 |
y:f64 | 8190584 | 8 |
x:i32 | 8190592 | 4 |
padding | 8190596 | 4 |
///////////////////////////////////////////////////////////
// user-defined traits act like interfaces //
// userdef.rs //
///////////////////////////////////////////////////////////
pub trait Speaker {
fn salutation(&self) -> String;
}
///////////////////////////////////////////////////////////
// The following structs act like classes that implement
// a Speaker interface
#[derive(Debug,Copy,Clone)]
pub struct Presenter;
impl Speaker for Presenter {
fn salutation(&self) -> String {
"Presenter: Hello, today we will discuss ...".to_string()
}
}
#[derive(Debug)]
pub struct Friend {
pub name : String,
}
impl Speaker for Friend {
fn salutation(&self) -> String {
let mut s = String::from("Friend: Hi good buddy, its me, ");
let nm = self.name.as_str();
s.push_str(nm);
return s;
}
}
impl Friend {
#[allow(dead_code)]
pub fn new(name : String) -> Self {
Self {
name,
} // note: no semicolon so Self is returned
}
}
#[derive(Debug,Copy,Clone)]
pub struct TeamLead;
impl Speaker for TeamLead {
fn salutation(&self) -> String {
"TeamLead: Hi, I have a task for you ...".to_string()
}
}
///////////////////////////////////////////////////////////
// Demonstrate polymorphic operations using Rust Traits //
// user_def::main.rs //
///////////////////////////////////////////////////////////
mod userdef;
use userdef::*;
#[allow(dead_code)]
pub fn run() {
print!(
"\n\n {}",
"-- demo polymorphic struct instances --\n"
);
let presenter : Presenter = Presenter;
let joe : Friend = Friend::new("Joe".to_string());
let sue : Friend = Friend::new("Sue".to_string());
let team_lead : TeamLead = TeamLead;
let mut v :Vec<&dyn Speaker> = Vec::new();
v.push(&presenter);
v.push(&joe);
v.push(&sue);
v.push(&team_lead);
/*
Presenters, Friends, and TeamLeads are all Speakers, i.e.,
they implement the Speaker trait, so they all can be
treated uniformily, as speakers.
*/
for speaker in v.iter() {
print!("\n {:?}",speaker.salutation());
}
}
fn main() {
run();
}
-- demo polymorphic struct instances --
"Presenter: Hello, today we will discuss ..."
"Friend: Hi good buddy, its me, Joe"
"Friend: Hi good buddy, its me, Sue"
"TeamLead: Hi, I have a task for you ..."
use std::fmt::{*};
use display::{*};
/*-----------------------------------------
Non-copy arguments will be moved
*/
fn demo<T:Debug>(t:T) {
show_type(&t);
show_value(&t);
}
/*-----------------------------------------
ref so arguments will not be moved
*/
fn demo_ref<T>(t:&T) where T:Debug {
show_type(t);
show_value(t);
}
main_title("generics_probes");
let mut s = String::from("this is a test");
sub_title("demo_ref");
demo_ref(&s);
let pi = 3.1415927;
demo_ref(&pi);
s.push('Z');
putline();
sub_title("demo");
demo(s);
demo(pi);
// statement below won't compile - s moved
// s.push('Z');
putline();
demo_ref
----------
TypeId: alloc::string::String, size: 24
value: "this is a test"
TypeId: f64, size: 8
value: 3.1415927
demo
------
TypeId: alloc::string::String, size: 24
value: "this is a testZ"
TypeId: f64, size: 8
value: 3.1415927
use std::fmt::{*};
use display::{*};
#[allow(dead_code)]
#[derive(Debug, Clone)]
struct Point<T> { x:T, y:T, z:T, }
// Copy works because blittable,
// provided that T is blittable
#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
struct BetterPoint<T> { x:T, y:T, z:T, }
sub_title("demo_ref and demo with struct");
let mut pt = Point { x:1.0, y:-1.5, z:2.3 };
demo_ref(&pt);
pt.x = 3.2;
demo(pt);
// statement below won't compile - pt moved for demo
// pt.x = 3.2;
putline();
sub_title("demo_ref and demo with copy-able struct");
let mut bpt = BetterPoint { x:1.0, y:-1.5, z:2.3 };
demo_ref(&bpt);
bpt.x = 3.2;
demo(bpt);
// statement ok - pt copied for demo
bpt.x = 3.2;
putline();
/* literal strings are type &str and are copy-able */
sub_title("demo_ref and demo with copy-able struct");
let mut bpt = BetterPoint { x:"one", y:"two", z:"three" };
demo_ref(&bpt);
bpt.x = "1";
demo(bpt);
// statement ok - pt copied for demo
bpt.x = "one";
putline();
sub_title("demo_ref and demo with non copy-able struct");
let mut bpt = BetterPoint {
x:"one".to_string(),
y:"two".to_string(),
z:"three".to_string()
};
demo_ref(&bpt);
bpt.x = "four".to_string();
demo(bpt);
// statement won't compile - pt not blittable
// bpt.x = "one".to_string();
putlinen(2);
}
demo_ref and demo with struct
-------------------------------
TypeId: generics_probes::Point, size: 24
value: Point { x: 1.0, y: -1.5, z: 2.3 }
TypeId: generics_probes::Point, size: 24
value: Point { x: 3.2, y: -1.5, z: 2.3 }
demo_ref and demo with copy-able struct
-----------------------------------------
TypeId: generics_probes::BetterPoint, size: 24
value: BetterPoint { x: 1.0, y: -1.5, z: 2.3 }
TypeId: generics_probes::BetterPoint, size: 24
value: BetterPoint { x: 3.2, y: -1.5, z: 2.3 }
demo_ref and demo with copy-able struct
-----------------------------------------
TypeId: generics_probes::BetterPoint<&str>, size: 48
value: BetterPoint { x: "one", y: "two", z: "three" }
TypeId: generics_probes::BetterPoint<&str>, size: 48
value: BetterPoint { x: "1", y: "two", z: "three" }
demo_ref and demo with non copy-able struct
---------------------------------------------
TypeId: generics_probes::BetterPoint, size: 72
value: BetterPoint { x: "one", y: "two", z: "three" }
TypeId: generics_probes::BetterPoint, size: 72
value: BetterPoint { x: "four", y: "two", z: "three" }
Reference Link | Description |
---|---|
Why Rust? - Jim Blandy | Monograph on why Rust is important |
Rust users forum | Answers to a broad range of questions from beginner to advanced. |
A half-hour to learn Rust | Code fragments with commentary that cover most of the Rust ideas. |
Rust by Example | Rust docs - walkthrough of syntax |
Rust Cookbook | Rust docs - a collection of example projects using the Rust libraries and external crates |
A Gentle Introduction To Rust | Read early in your Rust travels. |
The Rust Book | Rust docs - walkthrough of syntax |
Rust cheat sheet | Quite extensive list of cheats and helpers. |
Rust Containers | Container diagrams |
The Rust Reference Book | Rust's approximation of a language standard. Clear and well written, with a glossary at the end. Its github site shows that changes are still being actively incorporated. |
RIP Tutorial on Rust | Comprehensive coverage from RIP, the stackoverflow archive |
Learning Rust ebook | Comprehensive coverage from RIP, stackoverflow archive |
Rust - Awesome Book | lots of interesting discussions from RIP, the Stackoverflow Archive |
Shared reference &T and exclusive reference &mut T | More accurate description than immutable reference and mutable reference |
Getting Started with Rust on Windows and Visual Studio Code | Install Rust, Verify, Configure Visual Studio Code, Create Hello World, Create Build Task, Configuring Unit Tests, Configure Debugging, |
rust-lang.org home page | Links to download and documentation |
(video) Rust - Crash Course | Rustlang | Code demo using basic types. |
Tutorial - tutorialspoint.com | Tutorials for most of the Rust parts with code examples. |
Blog - Pascal's Scribbles | Pascal Hertleif - Rust contributor |
Blog - Barely Functional | Michael Gattozzi - Rust contributor |
Blog - S.Noyberg | Examples of aysnc/await, tokio, lifetime, ... |
Compilation details | kmcallister.github.io |