= rust one of the first slides about rust: http://venge.net/graydon/talks/intro-talk-2.pdf RustConf effects talk: https://www.youtube.com/watch?v=MTnIexTt9Dk&t=924s blog post: https://blog.yoshuawuyts.com/extending-rusts-effect-system/#stage-ii-effect-generic-bounds-impls-and-types effects: • try? • const generic • generic associated types (GAT) • async/.await == cargo and compilation cargo +nightly build -z timings cargo bloat --release --crate #![no_std] --target=riscv32i-unknown-none-elf == compiler guarantees The compiler guarantees (except unsafe{}) that Rust programs do not • Access memory out-of-bounds • Access memory after it has been freed • Execute the "wrong" code • Have data races Soundness is the property of an API to avoid Undefined Behavior when called from safe code Unsound code is a library that can be used by safe code to cause undefined behavior === compile with MIRI rustup toolchain install nightly --component miri cargo +nightly miri run # run MIRI at runtime cargo +nightly miri test cargo clean set-env MIRIFLAGS "-Zmiri-disable-isolation" cargo +nightly miri run == ownership model notes let m: i32 = 5; let mut n: i32 = 3; n = m; n += 1; m == 4 # copy content of `m` to `n`, then increment let m: &mut M = &mut M{a: 3, b: 5}; { let mut n: &mut M = &mut M{a: 7, b: 8}; n = m; n.a += 1; } m.a # rebind m to n, scoping is necessary, otherwise two mutable refs 'a: 'b … means “'a outlives 'b” == modularization (https://stackoverflow.com/q/57756927) mod module; … module.rs or module/mod.rs required mod self::module; … same (more explicit way in lib.rs) pub mod module; … module.rs or module/mod.rs required and is accessible if this module is imported extern crate mycrate; … linking step required to find this crate use mycrate::func;  … import func identifier from dependency mycrate use mycrate::{self, func}; … import func identifier from dependency mycrate and import mycrate as well use super::func;  … import func identifier from one level up in hierarchy pub use mycrate::func; … re-export other crate's functionality as part of your own crate foo::bar() … bar function of foo (which depends on known modules and crates) ::foo::bar() … bar function looked up by absolute path in current crate == custom Error types use std::error; use std::fmt; #[derive(Debug)] enum LibErrors { FileExists(String), } impl fmt::Display for LibErrors { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::FileExists(filepath) => write!(f, "file '{}' already exists, delete before running this program", filepath) } } } // implementation of suggested traits for custom Error types impl std::error::Error for LibErrors {} unsafe impl Send for LibErrors {} unsafe impl Sync for LibErrors {} == blanket implementation equivalence impl<'s> TryInto for StrArg { type Error = errors::Errors; fn try_into(self) -> Result { match self.0.parse::() { Ok(int) => Ok(int), Err(_) => Err(errors::Errors::ArgValueError(self.1, format!("cannot be converted into an integer: '{}'", self.0))), } } } ... is already provided by a blanket implementation if you implement ... impl<'s> TryFrom for u64 { type Error = errors::Errors; fn try_from(value: StrArg) -> Result { match value.0.parse::() { Ok(int) => Ok(int), Err(_) => Err(errors::Errors::ArgValueError(value.1, format!("cannot be converted into an integer: '{}'", value.0))), } } } == fetch Some(…) or a default value let x = Some(1); x.unwrap_or(42) == unsafe via https://doc.rust-lang.org/nomicon/what-unsafe-does.html superpowers: 1. Calling a function marked unsafe, non-Rust external function, or a compiler intrinsic (a function whose implementation is handled specially by the compiler) 2. Dereferencing a C-style pointer 3. Accessing a mutable global variable 4. Using inline assembly instructions 5. Accessing a field of a union type … rust still borrow-checks or verifies lifetimes. Implementor needs to guarantee: * no dereferencing of dangling or unaligned pointers * don't break: A reference cannot outlive its referent. A mutable reference cannot be aliased. * no data races * don't execute code compiled with target features that the current thread of execution does not support * don't produce invalid values Rust allows in safe & unsafe rust: • deadlock • race conditions • leak memory • fail to call destructor • integer overflow • abort the program • … == encode u16 array as string vice versa use hex; fn u16arr_to_string(input: &[u16]) -> String { let mut s = String::new(); for i in 0..input.len() { let split = input[i].to_be_bytes(); s.push_str(&hex::encode_upper(&split)); } s } fn string_to_u16arr(input: &str) -> Vec { let mut tmp = vec![0u8; input.len() / 2]; if let Err(e) = hex::decode_to_slice(input, &mut tmp) { panic!("decoding hex error: {}", e); } let mut arr = Vec::new(); for i in 0..(tmp.len() / 2) { let mut data = [0u8; 2]; data.copy_from_slice(&tmp[2*i..2*i+2]); arr.push(u16::from_be_bytes(data)); } arr } == pseudo-hash an array use std::ops::BitXorAssign; fn array_hash(arr: &[T]) -> T where T: BitXorAssign + Copy + std::ops::Add { let mut result = arr[0]; for i in 1..arr.len() { result ^= arr[i] + arr[i - 1]; } result } == rust ref matching == Some(10) AND match Some(ref member) => member has type "&i32" Some(10) AND match Some(member) => member has type "i32" Some(10) AND match Some(&member) => does not compile Some(Vec) AND match Some(ref member) => member has type "&Vec" Some(Vec) AND match Some(member) => member has type "Vec" Some(Vec) AND match Some(&member) => does not compile for item in vec![3] { let _: u32 = item; } => compiles for item in vec![3].iter() { let _: u32 = item; } => does not compile for item in vec![3].iter() { let _: &u32 = item; } => compiles for &item in vec![3].iter() { let _: u32 = item; } => compiles for ref item in vec![3].iter() { let _: &&u32 = item; } => compiles "if let" does not allow "ref" keyword. ref/ref mut -> "I want to borrow, not move", there is a value but I only need a reference move -> "I want to move" (used per default if no "&" is discovered in the match-argument) "&" -> "I expect a reference here", does actual referencing/dereferencing "&Foo(foo)" does not match enum X { Foo(u32) } match enum_value { X::Foo(int) => { let _: u32 = int; } } => compiles match enum_value { &X::Foo(int) => { let _: u32 = int; } } => does not compile, enum_value is not a reference match &enum_value { &X::Foo(int) => { let _: u32 = int; } } => compiles match enum_value { X::Foo(&int) => { let _: u32 = int; } } => does not compile, integer in Foo is not a reference match enum_value { X::Foo(ref int) => { let _: &u32 = int; } } => compiles match enum_value { ref X::Foo(int) => { let _: &u32 = int; } } => does not compile, invalid syntax enum X { Foo(String) } match enum_value { X::Foo(text) => { let _: String = text; } } => compiles match enum_value { &X::Foo(text) => { let _: String = text; } } => does not compile, enum_value is not a reference match &enum_value { &X::Foo(text) => { let _: String = text; } } => does not compile, cannot move out of shared reference match enum_value { X::Foo(&text) => { let _: String = text; } } => does not compile, mismatched type (unexpected reference String in "&text") match enum_value { X::Foo(ref text) => { let _: &str = text; } } => compiles match enum_value { ref X::Foo(text) => { let _: &str = text; } } => does not compile, invalid syntax • The iterator returned by into_iter may yield any of T, &T or &mut T, depending on the context (enables a for loop). • The iterator returned by iter will yield &T, by convention. • The iterator returned by iter_mut will yield &mut T, by convention. == smart pointer equivalents in rust === single-threaded unique_ptr … ownership transfer shared_ptr … Rc weak_ptr … rc::Weak auto_ptr (deprecated since C++11) … Rc new … Box Cells enable interior mutability (allow mutability even if the object (Cell is part of) is declared immutable): Cell:: implemented by swapping/copying, circumvents aliasing/borrowing; use only for small objects, requires Copy RefCell:: implemented with runtime checks, mutable & read-only borrowing checked at runtime, use for any objects, requires only Sized OnceCell:: can only be written once === multi-threaded unique_ptr … ownership transfer shared_ptr … Arc weak_ptr … rc::Weak auto_ptr (deprecated since C++11) … Arc new … Box sync::RwLock:: implemented with runtime checks, mutable & read-only borrowing checked at runtime, use for any objects, requires only Sized sync::OnceLock:: can only be written once === API naming conventions https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv ============= ========== ================================== Prefix Cost Ownership ------------- ---------- ---------------------------------- as_ Free borrowed -> borrowed to_ Expensive borrowed -> borrowed borrowed -> owned (non-Copy types) owned -> owned (Copy types) into_ Variable owned -> owned (non-Copy types) ============= ========== ==================================