Skip to content
Snippets Groups Projects
Commit 007df026 authored by orestis.malaspin's avatar orestis.malaspin
Browse files

Merge branch 'unsafe' into 'main'

Unsafe chapter was added

Closes #29

See merge request orestis.malaspin/rust-101!37
parents fe15003f d23c9402
No related branches found
No related tags found
No related merge requests found
Showing
with 3610 additions and 13 deletions
...@@ -4,11 +4,12 @@ image: "rust:1-slim-bookworm" ...@@ -4,11 +4,12 @@ image: "rust:1-slim-bookworm"
# Use cargo to test the project # Use cargo to test the project
before_script: before_script:
- apt update && apt upgrade -y - apt update && apt upgrade -y
- apt install curl unzip -y - apt install curl unzip xz-utils -y
- mkdir -p $HOME/.cargo/bin - mkdir -p $HOME/.cargo/bin
- curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.31/mdbook-v0.4.31-x86_64-unknown-linux-musl.tar.gz | tar -xz --directory=$HOME/.cargo/bin - curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.31/mdbook-v0.4.31-x86_64-unknown-linux-musl.tar.gz | tar -xz --directory=$HOME/.cargo/bin
- curl -L https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases/download/v0.7.7/mdbook-linkcheck.x86_64-unknown-linux-gnu.zip -o mdbook-linkcheck.zip - curl -L https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases/download/v0.7.7/mdbook-linkcheck.x86_64-unknown-linux-gnu.zip -o mdbook-linkcheck.zip
- unzip mdbook-linkcheck.zip -d $HOME/.cargo/bin && chmod +x $HOME/.cargo/bin/mdbook-linkcheck - unzip mdbook-linkcheck.zip -d $HOME/.cargo/bin && chmod +x $HOME/.cargo/bin/mdbook-linkcheck
- curl -sSL https://github.com/ferrous-systems/mdslides/releases/download/v0.3.0/mdslides-v0.3.0-x86_64-unknown-linux-gnu.tar.xz | tar -xJ "mdslides-v0.3.0-x86_64-unknown-linux-gnu/mdslides" && mv mdslides-v0.3.0-x86_64-unknown-linux-gnu/mdslides $HOME/.cargo/bin/ && rm -r mdslides-v0.3.0-x86_64-unknown-linux-gnu
- rustup component add rustfmt - rustup component add rustfmt
- rustup component add clippy - rustup component add clippy
- export PATH=$PATH:$HOME/.cargo/bin - export PATH=$PATH:$HOME/.cargo/bin
...@@ -64,6 +65,12 @@ build:book: ...@@ -64,6 +65,12 @@ build:book:
- cd book - cd book
- mdbook test - mdbook test
- mdbook build - mdbook build
build:slides:
stage: build
script:
- cd slides
- ./build_slides.sh
deploy:book: deploy:book:
stage: deploy stage: deploy
...@@ -72,4 +79,13 @@ deploy:book: ...@@ -72,4 +79,13 @@ deploy:book:
script: script:
- cd book - cd book
- mdbook build - mdbook build
- rsync -avz book/* ur1bg_malas@ur1bg.ftp.infomaniak.com:web/malaspinas/rust-101/ - rsync -avz book/html/* ur1bg_malas@ur1bg.ftp.infomaniak.com:web/malaspinas/rust-101/book/
deploy:slides:
stage: deploy
only:
- main
script:
- cd slides
- ./build_slides.sh
- rsync -avz slides ur1bg_malas@ur1bg.ftp.infomaniak.com:web/malaspinas/rust-101/
...@@ -8,15 +8,15 @@ title = "Rust-101: Université d'été" ...@@ -8,15 +8,15 @@ title = "Rust-101: Université d'été"
[output.html.playground] [output.html.playground]
editable = true editable = true
# [output.linkcheck] [output.linkcheck]
# # Should we check links on the internet? Enabling this option adds a # Should we check links on the internet? Enabling this option adds a
# # non-negligible performance impact # non-negligible performance impact
# follow-web-links = true follow-web-links = true
# # How should warnings be treated? # How should warnings be treated?
# # #
# # - "warn" will emit warning messages # - "warn" will emit warning messages
# # - "error" treats all warnings as errors, failing the linkcheck # - "error" treats all warnings as errors, failing the linkcheck
# # - "ignore" will ignore warnings, suppressing diagnostic messages and allowing # - "ignore" will ignore warnings, suppressing diagnostic messages and allowing
# # the linkcheck to continuing # the linkcheck to continuing
# warning-policy = "error" warning-policy = "error"
...@@ -14,3 +14,4 @@ ...@@ -14,3 +14,4 @@
- [Part 09](./part09.md) - [Part 09](./part09.md)
- [Part 10](./part10.md) - [Part 10](./part10.md)
- [Part 11](./part11.md) - [Part 11](./part11.md)
- [Part 12](./part12.md)
# Discussion du code `part07`
# Part 08
# Part 09
# Pointeurs intelligents et mémoire
\ No newline at end of file
# Part 11
This diff is collapsed.
[package]
name = "linked_list"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
// ANCHOR: element
struct Element {
data: i32,
next: Option<Box<Element>>,
}
// ANCHOR_END: element
impl Element {
fn new(data: i32, next: Option<Box<Element>>) -> Self {
Element { data, next }
}
}
// ANCHOR: linked_list
pub struct LinkedList {
head: Option<Box<Element>>,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: new
pub fn new() -> Self {
Self { head: None }
}
// ANCHOR_END: new
// ANCHOR: is_empty
pub fn is_empty(self) -> (bool, Self) {
match self.head {
None => (true, self),
_ => (false, self),
}
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(self, data: i32) -> Self {
let elem = Box::new(Element::new(data, self.head));
Self { head: Some(elem) }
}
// ANCHOR_END: push
// ANCHOR: pop
pub fn pop(self) -> (Option<i32>, Self) {
if let Some(elem) = self.head {
(Some(elem.data), Self { head: elem.next })
} else {
(None, Self { head: None })
}
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(self) -> Self {
let mut new_list = Self::new();
// ANCHOR: while
let mut current = self.head;
while let Some(tmp) = current {
print!("{} --> ", tmp.data);
new_list = new_list.push(tmp.data);
current = tmp.next;
}
println!("∅");
// ANCHOR_END: while
new_list
}
// ANCHOR_END: print
#[allow(dead_code)]
// ANCHOR: clear
pub fn clear(self) {
let mut current = self.head;
while let Some(tmp) = current {
current = tmp.next;
}
}
// ANCHOR_END: clear
}
#[cfg(test)]
mod tests {
use super::LinkedList;
#[test]
fn new() {
let (is_empty, _) = LinkedList::new().is_empty();
assert!(is_empty);
}
#[test]
fn push() {
let list = LinkedList::new();
let list = list.push(1);
let (is_empty, list) = list.is_empty();
assert!(!is_empty);
assert_eq!(list.head.as_ref().unwrap().data, 1);
let list = list.push(2);
assert_eq!(list.head.unwrap().data, 2);
}
#[test]
fn pop() {
let list = LinkedList::new();
let (e, list) = list.pop();
assert_eq!(e, None);
let list = list.push(1);
let (e, list) = list.pop();
assert_eq!(e, Some(1));
let (e, list) = list.pop();
assert_eq!(e, None);
let list = list.push(2);
let list = list.push(3);
let list = list.push(4);
assert_eq!(list.head.as_ref().unwrap().data, 4);
let (e, list) = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 3);
assert_eq!(e, Some(4));
let (_, list) = list.pop();
let (_, list) = list.pop();
let (is_empty, _) = list.is_empty();
assert!(is_empty);
}
}
pub mod immutable_linked_list;
pub mod safe_linked_list;
pub mod unsafe_linked_list;
use linked_list::immutable_linked_list::LinkedList as ImmutableList;
use linked_list::safe_linked_list::LinkedList as SafeList;
use linked_list::unsafe_linked_list::LinkedList as UnsafeList;
fn create_lists() -> (ImmutableList, SafeList, UnsafeList) {
(ImmutableList::new(), SafeList::new(), UnsafeList::new())
}
fn main() {
let (immutable_list, mut safe_list, mut unsafe_list) = create_lists();
// Populate lists
let immutable_list = immutable_list.push(1);
let immutable_list = immutable_list.push(2);
let immutable_list = immutable_list.push(3);
safe_list.push(1);
safe_list.push(2);
safe_list.push(3);
unsafe_list.push(1);
unsafe_list.push(2);
unsafe_list.push(3);
let (i_val, immutable_list) = immutable_list.pop();
let s_val = safe_list.pop();
let u_val = unsafe_list.pop();
assert_eq!(i_val, s_val);
assert_eq!(i_val, u_val);
assert_eq!(s_val, u_val);
let immutable_list = immutable_list.push(4);
safe_list.push(4);
unsafe_list.push(4);
immutable_list.print();
safe_list.print();
unsafe_list.print();
for j in 1..1000 {
let mut ul = UnsafeList::new();
for i in 1..1_000_000 {
ul.push(i);
}
}
unsafe_list.print();
}
// ANCHOR: element
struct Element {
data: i32,
next: Option<Box<Element>>,
}
// ANCHOR_END: element
impl Element {
fn new(data: i32, next: Option<Box<Element>>) -> Self {
Element { data, next }
}
}
// ANCHOR: linked_list
pub struct LinkedList {
head: Option<Box<Element>>,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: new
pub fn new() -> Self {
Self { head: None }
}
// ANCHOR_END: new
// ANCHOR: is_empty
pub fn is_empty(&self) -> bool {
self.head.is_none()
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(&mut self, data: i32) {
// let new_element = Box::new(Element::new(data, self.head));
// Cela ne peut pas fonctionner, pace qu'on est derrière une référence partagée
// et donc on peut pas "move" self.head
// ANCHOR: take
let new_head = Box::new(Element::new(data, self.head.take()));
// ANCHOR_END: take
// take retourne la valeur qui se trouve dans Some et laisse un None
// à la place de l'option.
// C'est strictement équivalent au replace (ci-dessous)
self.head = Some(new_head);
}
// ANCHOR_END: push
// ANCHOR: push_replace
pub fn push_replace(&mut self, data: i32) {
// ANCHOR: replace
let old_head = std::mem::replace(&mut self.head, None);
let new_head = Box::new(Element::new(data, old_head));
// ANCHOR: replace
// replace retourne self.head et remplace l'ancienne valeur par None (comme ça le compilateur est content)
self.head = Some(new_head);
}
// ANCHOR_END: push_replace
// ANCHOR: push_unsafe
pub fn push_unsafe(&mut self, data: i32) {
let old_head = unsafe {
// De la documentation:
// `read` crée une copie bit à bit de `T`, que `T` soit [`Copy`] ou non.
// Si `T` n'est pas [`Copy`], utiliser à la fois la valeur renvoyée et la valeur de
// `*src` peut violer la sécurité de la mémoire. Notez que l'assignation à `*src` compte comme une
// utilisation parce qu'elle tentera de `drop` la valeur à `*src`.
let result = std::ptr::read(&self.head);
std::ptr::write(&mut self.head, None);
// Ce `write` est en fait un "truc" pour enlever l'aliasing entre
// self.head et result. Il écrase la valeur à self.head avec None
// sans `drop` self.head et donc result.
result
};
let new_head = Box::new(Element::new(data, old_head));
self.head = Some(new_head);
}
// ANCHOR_END: push_unsafe
// ANCHOR: pop
pub fn pop(&mut self) -> Option<i32> {
// map prend la valeur dans Some, lui applique la fonction anonyme
// et remballe la valeur obtenue dans un Some. Si l'Option
// originale est None, il se passe rien.
self.head.take().map(|element| {
self.head = element.next;
element.data
})
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(&self) {
let mut current = &self.head;
while let Some(tmp) = &current {
print!("{} --> ", tmp.data);
current = &tmp.next;
}
println!("∅");
}
// ANCHOR_END: print
}
impl Drop for LinkedList {
fn drop(&mut self) {
let mut current = self.head.take();
while let Some(mut tmp) = current {
current = tmp.next.take();
}
}
}
#[cfg(test)]
mod test {
use super::LinkedList;
#[test]
fn new() {
assert!(LinkedList::new().is_empty());
}
#[test]
fn push() {
let mut list = LinkedList::new();
list.push(1);
assert_eq!(list.head.as_ref().unwrap().data, 1);
list.push(2);
assert_eq!(list.head.as_ref().unwrap().data, 2);
}
#[test]
fn pop() {
let mut list = LinkedList::new();
let e = list.pop();
assert_eq!(e, None);
list.push(1);
let e = list.pop();
assert_eq!(e, Some(1));
let e = list.pop();
assert_eq!(e, None);
list.push(2);
list.push(3);
list.push(4);
assert_eq!(list.head.as_ref().unwrap().data, 4);
let e = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 3);
assert_eq!(e, Some(4));
list.push(5);
list.push(6);
let e = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 5);
assert_eq!(e, Some(6));
}
}
use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
use std::ptr;
// ANCHOR: element
struct Element {
data: i32,
next: *mut Element,
}
// ANCHOR_END: element
impl Element {
// ANCHOR: new
fn new(data: i32, next: *mut Element) -> *mut Element {
let layout = Layout::new::<Element>();
let e = unsafe { alloc(layout) as *mut Element };
if e.is_null() {
handle_alloc_error(layout);
}
unsafe {
(*e).data = data;
(*e).next = next;
}
e
}
// ANCHOR_END: new
}
//ANCHOR: drop
impl Drop for Element {
fn drop(&mut self) {
let elem = self as *mut Element;
if !elem.is_null() {
let layout = Layout::new::<Element>();
unsafe {
dealloc(elem as *mut u8, layout);
}
}
}
}
//ANCHOR_END: drop
// ANCHOR: linked_list
pub struct LinkedList {
head: *mut Element,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: ll_new
pub fn new() -> LinkedList {
LinkedList {
head: ptr::null_mut(),
}
}
// ANCHOR_END: ll_new
// ANCHOR: is_empty
fn is_empty(&self) -> bool {
self.head.is_null()
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(&mut self, data: i32) {
let new_head = Element::new(data, self.head);
self.head = new_head;
}
// ANCHOR_END: push
// ANCHOR: pop
pub fn pop(&mut self) -> Option<i32> {
if self.is_empty() {
None
} else {
let old_head = self.head;
unsafe {
self.head = (*self.head).next;
}
let val = unsafe { (*old_head).data };
unsafe {
old_head.drop_in_place();
}
Some(val)
}
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(&self) {
let mut current_head = self.head;
while !current_head.is_null() {
unsafe {
print!("{} --> ", (*current_head).data);
current_head = (*current_head).next;
}
}
println!("∅");
}
// ANCHOR_END: print
}
// ANCHOR: ll_drop
impl Drop for LinkedList {
fn drop(&mut self) {
while !self.is_empty() {
let _ = self.pop();
}
}
}
// ANCHOR_END: ll_drop
#[cfg(test)]
mod tests {
use super::LinkedList;
#[test]
fn new() {
assert!(LinkedList::new().is_empty());
}
#[test]
fn push() {
let mut list = LinkedList::new();
list.push(1);
assert_eq!(unsafe { (*list.head).data }, 1);
list.push(2);
assert_eq!(unsafe { (*list.head).data }, 2);
}
#[test]
fn pop() {
let mut list = LinkedList::new();
let e = list.pop();
assert_eq!(e, None);
list.push(1);
let e = list.pop();
assert_eq!(e, Some(1));
let e = list.pop();
assert_eq!(e, None);
list.push(2);
list.push(3);
list.push(4);
assert_eq!(unsafe { (*list.head).data }, 4);
let e = list.pop();
assert_eq!(unsafe { (*list.head).data }, 3);
assert_eq!(e, Some(4));
list.push(5);
list.push(6);
let e = list.pop();
assert_eq!(unsafe { (*list.head).data }, 5);
assert_eq!(e, Some(6));
}
}
book
slides
[book]
authors = ["Orestis"]
language = "en"
multilingual = false
src = "src"
title = "Université d'été 2023: Rust 101"
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Build the book first, because mdbook will create any empty sections
echo "Building book"
RUST_LOG=info mdbook build ${SCRIPT_DIR}
# Then build the slides
echo "Building slides"
RUST_LOG=debug mdslides --template ${SCRIPT_DIR}/template.html --output-dir ${SCRIPT_DIR}/slides --mdbook-path ${SCRIPT_DIR} --index-template ${SCRIPT_DIR}/index-template.html
# TODO: move assets copying to mdslides
cp -r "${SCRIPT_DIR}/book/figs" "${SCRIPT_DIR}/slides"
# Then run the tests (which is slow)
echo "Testing book"
RUST_LOG=info mdbook test ${SCRIPT_DIR}
\ No newline at end of file
This diff is collapsed.
# Table des matières du cours
- [Introduction](introduction.md)
- [Installation](installation.md).
- [Variables](variables.md).
- [Types](types.md).
- [Structures de contrôle](control.md).
- [Types avancés](types_avances.md).
- [Organisation du code](modules.md).
- [Fonctions](fonctions.md).
- [Ownership](ownership.md).
- [Commentaires](commentaires.md).
- [Gestion d'erreurs](errors.md).
- [Méthodes](methods.md).
- [Pointeurs intelligents](smart_pointers.md).
- [Génériques](generics.md).
- [Traits](traits.md).
- [Tests](tests.md).
- [Vecteurs](vec.md).
<!-- - [Itérateurs](iterators.md).
- [Unsafe Rust](collections.md).
- [Lifetimes](lifetimes.md). -->
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment