diff --git a/book/book.toml b/book/book.toml
index 9a31d1e76990f25a14ecdbc82df88213983dd9dd..fb0a61ec4b4905ea1919421cfdd947bfee421da1 100644
--- a/book/book.toml
+++ b/book/book.toml
@@ -4,3 +4,6 @@ language = "fr"
 multilingual = false
 src = "src"
 title = "Rust-101: Université d'été"
+
+[output.html.playground]
+editable = true
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index 23058d8797235a29e67c15c12beaa131ab622544..e128166e93532a0dfe5c7c505e3fc73848ebaa77 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -3,3 +3,4 @@
 - [Part 00](./part00.md)
 - [Part 01](./part01.md)
 - [Part 02](./part02.md)
+- [Part 03](./part03.md)
diff --git a/book/src/part03.md b/book/src/part03.md
new file mode 100644
index 0000000000000000000000000000000000000000..2056a3923eb78ca1daaf1e25539dd69a5a745d3f
--- /dev/null
+++ b/book/src/part03.md
@@ -0,0 +1,275 @@
+# Discussion du code `part03`
+
+Dans cette partie nous discutons de [ce code](#le-code).
+
+## Concepts
+
+Les concepts abordés dans cet exemple sont:
+
+1. [La généricité et les traits.](#la-généricité-et-les-traits)
+2. [Le trait `Minimum`.](#le-trait-minimum)
+3. [Les tuples](#les-tuples)
+4. [Les traits `Clone` et `Copy`.](#les-traits-clone-et-copy)
+
+## Discussion
+
+### La généricité et les traits
+
+En Rust (comme dans beaucoup de langages) on a un moyen d'éviter de dupliquer du code en
+utilisant le concept de *généricité*. Il s'agit ici de remplacer un type par un caractère générique
+lors de la définition d'un type ou d'une fonction.
+
+Jusqu'ici nous avions une structure `NumberOrNothing` qui contenait soit `Nothing` soit `Number(i32)` qui encapsule un entier 32 bits. Afin d'éviter de devoir réécrire tout le code pour chaque
+type (`u64`, `double`, ou n'importe quel autre type) on va réécrire notre type énuméré
+en le renommant astucieusement `SomethingOrNothing` (en effet, il se pourrait que nous ne voulions
+plus uniquement trouver le plus petit nombre dans une liste, mais on pourrait vouloir
+trouver le mot le plus "petit" dans l'ordre lexicographique). Ainsi on a
+
+```rust,no_run
+{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
+```
+
+Il faut noter ici la présence du caractère générique `T`, qui est déclaré comme générique
+lors de la définition du type `SomethingOrNothing<T>`, puis est utilisé à la place de `i32`
+dans `Something(T)`.
+
+Maintenant qu'on a changé la définition de noter type, plus rien fonctionne et on doit adapter
+le reste du code. Pour aller dans l'ordre, on doit modifier l'implémentation de la fonction `SomethingOrNothing::new(val)`
+
+```rust,no_run
+{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
+{{#include ../../codes/rust_lang/part03/src/main.rs:new}}
+```
+
+On voit ici qu'il faut annoter tout le bloc `impl<T> SomethingOrNothing<T>` avec le type générique
+afin qu'il puisse être réutilisé dans les fonctions statiques. En effet,
+si on omet les `<T>` on une erreur de compilation
+```rust,compile_fail
+{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
+impl SomethingOrNothing<T> {
+    fn new(val: T) -> SomethingOrNothing<T> {
+        SomethingOrNothing::Something(val)
+    }
+}
+```
+
+Afin d'illustrer une particularité de la généricité de Rust, nous avons également réécrit la fonction
+`print(val)`
+```rust,no_run
+{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
+{{#include ../../codes/rust_lang/part03/src/main.rs:print}}
+```
+On voit ici qu'il y a une annotation particulière dans l'entête de la fonction, `T: std::fmt::Display`
+```rust,ignore
+fn print<T: std::fmt::Display>(val: SomethingOrNothing<T>)
+```
+Cette syntaxe dit au compilateur que le type générique implémente une fonctionnalité 
+particulière, nommée **trait**, qui dit au programme comment afficher une variable du type
+générique `T`. On voit qu'on doit afficher la valeur `val` encapsulée dans `Something(val)`
+
+```rust,ignore
+SomethingOrNothing::Something(val) => println!("Something is: {}", val),
+```
+
+Hors si on ne dit pas à notre programme comment faire cet affichage, il sera bien embêté. Ici,
+nous devons donc préciser qu'il est **nécessaire** que `T` implémente le trait `Display`
+sinon le programme ne compilera pas (cliquez sur play pour le vérifier)
+```rust,compile_fail
+{{#include ../../codes/rust_lang/part03/src/main.rs:something_or_nothing}}
+fn print<T>(val: SomethingOrNothing<T>) {
+    match val {
+        SomethingOrNothing::Nothing => println!("Nothing."),
+        SomethingOrNothing::Something(val) => println!("Something is: {}", val),
+    }
+}
+```
+On retrouve la contrainte d'implémenter le trait `Display` dans la fonction `print_tab(tab)`.
+Corriger le code ci-dessous pour qu'il compile
+```rust,compile_fail,editable
+const SIZE: usize = 9;
+fn read_command_line() -> [i32; SIZE] {
+    [10, 32, 12, 43, 52, 53, 83, 2, 9]
+}
+fn print_tab<T>(tab: [T; SIZE]) {
+    for t in tab {
+        print!("{} ", t);
+    }
+    println!();
+}
+fn main() {
+    print_tab(read_command_line());
+}
+```
+
+### Le trait `Minimum`
+
+La fonctionnalité principale dont nous avons besoin pour que notre code fonctionne est de pouvoir trouver
+le minimum d'une liste de `SomethingOrNothing<T>` (voir l'appel à la fonction `current_minimum.min(SomethingOrNothing::new(t))`).
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part03/src/main.rs:find_min}}
+```
+
+Ainsi on doit annoter `T` pour qu'il puisse calculer la plus petite valeur entre deux `SomethingOrNothing<T>`. On va donc devoir écrire définir notre premier *trait*.
+On définit un trait à l'aide de la syntaxe suivante
+```rust,no_run
+{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
+```
+Ici le trait `Minimum` sera implémenté sur un type qui implémente le trait `Copy` (un trait qui 
+garantit qu'on sait comment copier une valeur). Notre trait n'a que la fonction `min` (le nombre 
+de fonction dans un trait est arbitraire, il peut même être nul).
+L'entête de la fonction nous dit que la fonction `min` a deux argument, la variable sur laquelle 
+elle est appelée, et une variable du même type (annoté avec le type `Self`, avec un "s" 
+majuscule, contrairement à `self` qui fait référence à une variable) et retourne également une 
+valeur du même type.
+Il est important de vous rappeler qu'ici on ne sait pas encore quel est le type sur lequel on implémente cette fonction.
+
+L'implémentation de `Minimum` pour `SomethingOrNothing<T>` se fait comme suit
+
+```rust,ignore
+{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
+{{#include ../../codes/rust_lang/part03/src/main.rs:minimum_impl}}
+```
+
+Pour implémenter un trait sur un type on utilise la syntaxe
+
+```rust,ignore
+impl Trait for Type
+```
+
+puis implémenter **toutes** les fonctions se trouvant dans la définition du trait.
+Ici, nous n'avons que la fonction `min` à implémenter.
+
+Le type `SomethingOrNothing` est générique, donc il faut à nouveau notre code
+pour en tenir compte. On voit que le type générique doit lui-même
+implémenter le trait `Minimum` pour que cette fonction compile: on voit l'utilisation 
+de la fonction `min`
+
+```rust,ignore
+SomethingOrNothing::new(lhs.min(rhs))
+```
+
+Nous verrons le détail de la syntaxe de cette fonction dans la section sur [les tuples](#les-tuples). 
+
+Comme nous utilisons des `SomethingOrNothing<i32>` dans ce code, nous devons implémenter
+le trait `Minimum` pour des entiers. Ce qui est fait dans le bout de code suivant
+
+```rust,no_run
+{{#include ../../codes/rust_lang/part03/src/main.rs:minimum}}
+{{#include ../../codes/rust_lang/part03/src/main.rs:minimum_i32}}
+```
+
+### Les tuples
+
+On découvre ici, une syntaxe inconnue: les **tuples**. Un tuple est une collection
+d'un nombre arbitraire de valeurs dont les types peuvent être différents. 
+Un tuple lui-même est une valeur dont le type est
+
+```rust,ignore
+(T1, T2, T3, ...)
+```
+où `T1`, `T2`, `T3`, ... sont les types des membres du tuple. Un tuple peut être utilisé pour retourner plusieurs valeurs depuis une fonction par exemple.
+
+Ainsi quand on fait du *pattern mathching* 
+
+```rust,ignore
+match (self, rhs)
+```
+
+on va créer un tuple avec les valeurs de `self` et de `rhs` et vérifier les types de toutes les valeurs possibles pour ces types énumérées. On a donc 4 cas différents:
+
+```rust,ignore
+match (self, rhs) {
+    (SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => {
+        SomethingOrNothing::Nothing
+    }
+    (SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
+        SomethingOrNothing::new(lhs.min(rhs))
+    }
+    (SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
+        SomethingOrNothing::new(rhs)
+    }
+    (SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
+        SomethingOrNothing::new(lhs)
+    }
+}
+```
+
+quand on a deux variantes `Nothing`, on retourne `Nothing`, quand on a une variante `Nothing` 
+et une valeur `Something(val)` on retourne `Something(val)` et finalement quand on a 
+`Something(lhs)` et un `Something(rhs)`, c'est `Something(lhs.min(rhs))` qui est retourné (donc 
+la valeur la plus petite qui encapsulée). D'où la nécessité que `T` implémente le trait `Minimum`.
+Il faut noter à nouveau qu'il n'y a pas de `;` dans les blocs des variantes du pattern matching et que les valeurs sont retournées (la structure de contrôle `match` est une expression).
+
+### Les traits `Clone` et `Copy`
+
+En Rust, il existe deux traits essentiels `Copy` et `Clone`. Le trait `Copy` permet de copier les instances d'un type bit à bit. La copie est une action **implicite**. Par exemple, dans le code ci-dessous 
+
+```rust,ignore
+let y : i32 = 5;
+let x = y;
+```
+
+la valeur de `y` (ici `5`) est copiée dans une zone mémoire nouvellement allouée qui ensuite est liée à la variable `x`.
+Dans notre code nous décidons d'autoriser la copie de notre type énuméré en implémentant le trait `Copy`
+
+```rust,no_run
+{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:copy}}
+```
+
+Comme on peut le voir ici, il n'y a pas de fonction à implémenter avec `Copy`, ce trait permet uniquement d'effectuer une copie binaire des données.
+
+Il est également important de noter qu'afin que notre type `SomethingOrNothing<T>` implémente le trait `Copy`, il est nécessaire que le type paramètrique `T` implémente lui aussi `Copy`. Ce qui veut dire plus simplement qu'un type complexe ne peut pas implémenter le trait `Copy` si les types qu'il contient ne sont pas copiable.
+
+On peut aussi remarquer qu'il est possible d'indiquer la nécessité que les types implémentant un trait soit copiables. Par exemple
+
+```rust,no_run
+{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:minimum}}
+```
+où la notation `trait Minimum: Copy` spécifie que `Copy` doit être implémenté quand on implémente `Minimum`.
+Ici tous les types qui implémentent le trait `Minimum` doivent également implémenter `Copy`. C'est le cas par exemple du type `i32`
+
+```rust,no_run
+{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:minimum_i32}}
+```
+
+Le deuxième trait que nous retrouvons dans ce code est le trait `Clone`. `Clone` est un supertrait de `Copy`, ce qui signifie qu'un type qui implémente `Copy` doit nécessairement implémenter `Clone`.
+Le trait `Clone` permet de dupliquer explicitement une instance. En effet, pour cloner une instance, il faut appeler la méthode `clone()` explicitement
+
+```rust,no_run
+{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:clone}}
+```
+
+Comme on peut le voir dans le code ci-dessus, il est possible de définir  un comportement arbitraire en redéfinissant la méthode `clone()`. 
+En effet, le trait `Clone` nous permet de définir librement le comportement attendu lors d'un clonage, ce qui n'est pas le cas avec `Copy`. 
+Cette liberté a un coût, puisque que l'on peut écrire notre propre fonction de clonnage, ce dernier peut facilement devenir beaucoup plus coûteux que la simple copie binaire des données.
+
+Le langage Rust offre un attribut afin de pouvoir implémenter simplement les traits `Copy` et `Clone`. Il s'agit de `#[derive(...)]`.
+Par exemple avec le code suivant
+
+```rust,no_run
+#[derive(Clone,Copy)]
+struct MyStruct;
+```
+
+l'annotation permet d'indiquer au compilateur que notre `struct MyStruct` nécessite une implémentation par défaut des traits `Copy` et `Clone`. 
+Ce qui est équivaut à écrire
+
+```rust,no_run
+struct MyStruct;
+
+impl Copy for MyStruct { }
+
+impl Clone for MyStruct {
+    fn clone(&self) -> MyStruct {
+        *self
+    }
+}
+
+```
+
+## Le code
+
+```rust
+{{#rustdoc_include ../../codes/rust_lang/part03/src/main.rs:main}}
+```
diff --git a/codes/run_tests.sh b/codes/run_tests.sh
index feb0a29ac894795b6b4616658ab33ee2b1c2abf8..8c2e74c3c4c29afb4dde329ea2d9140ff8ae320a 100755
--- a/codes/run_tests.sh
+++ b/codes/run_tests.sh
@@ -4,7 +4,12 @@ make -C c_lang/min_list
 cd rust_lang
 for d in *; do
     echo ==================== Running cargo run for $d  ====================
-    cargo run --manifest-path $d/Cargo.toml
+    if [ $d == 'part07' ]
+    then
+        cargo run --manifest-path $d/Cargo.toml < $d/numbers.txt
+    else
+        cargo run --manifest-path $d/Cargo.toml
+    fi
     echo ==================== Running cargo test for $d ====================
     cargo test --manifest-path $d/Cargo.toml --workspace --verbose
     echo ==================== Running cargo doc for $d  ====================
diff --git a/codes/rust_lang/part03/src/main.rs b/codes/rust_lang/part03/src/main.rs
index 7cadbdc27915aa2495b46109fc526c770519620e..0f8ebd93ffd481640068449ac8679d6429ef3e92 100644
--- a/codes/rust_lang/part03/src/main.rs
+++ b/codes/rust_lang/part03/src/main.rs
@@ -1,39 +1,57 @@
+/* ANCHOR: all */
+
 /// In part03 we introduce genericity through traits and in particular, [Copy],
 /// [Clone], [std::fmt::Display] .
-
+// ANCHOR: something_or_nothing
 enum SomethingOrNothing<T> {
     Nothing,
     Something(T),
 }
+// ANCHOR_END: something_or_nothing
+
+// ANCHOR: new
+impl<T> SomethingOrNothing<T> {
+    fn new(val: T) -> SomethingOrNothing<T> {
+        SomethingOrNothing::Something(val)
+    }
+}
+// ANCHOR_END: new
 
+// ANCHOR: print
+// Print function
 // We know the generic type T must be Displayable
-impl<T: std::fmt::Display> SomethingOrNothing<T> {
-    // Static function
-    fn print(self) {
-        match self {
-            SomethingOrNothing::Nothing => println!("Nothing."),
-            SomethingOrNothing::Something(val) => println!("Something is: {}", val),
-        }
+fn print<T: std::fmt::Display>(val: SomethingOrNothing<T>) {
+    match val {
+        SomethingOrNothing::Nothing => println!("Nothing."),
+        SomethingOrNothing::Something(val) => println!("Something is: {}", val),
     }
 }
+// ANCHOR_END: print
 
+// ANCHOR: clone
 impl<T: Clone> Clone for SomethingOrNothing<T> {
     fn clone(&self) -> Self {
         match self {
             SomethingOrNothing::Nothing => SomethingOrNothing::Nothing,
-            SomethingOrNothing::Something(val) => SomethingOrNothing::Something(val.clone()),
+            SomethingOrNothing::Something(val) => SomethingOrNothing::new(val.clone()),
         }
     }
 }
+// ANCHOR_END: clone
 
+// ANCHOR: copy
 impl<T: Copy> Copy for SomethingOrNothing<T> {}
+// ANCHOR_END: copy
 
 // If we remove Copy, we have a problem with the t in tab
 // in the computation of the minimum.
+// ANCHOR: minimum
 trait Minimum: Copy {
     fn min(self, rhs: Self) -> Self;
 }
+// ANCHOR_END: minimum
 
+// ANCHOR: minimum_impl
 impl<T: Minimum> Minimum for SomethingOrNothing<T> {
     fn min(self, rhs: Self) -> Self {
         match (self, rhs) {
@@ -41,20 +59,22 @@ impl<T: Minimum> Minimum for SomethingOrNothing<T> {
                 SomethingOrNothing::Nothing
             }
             (SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
-                SomethingOrNothing::Something(lhs.min(rhs))
+                SomethingOrNothing::new(lhs.min(rhs))
             }
             (SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
-                SomethingOrNothing::Something(rhs)
+                SomethingOrNothing::new(rhs)
             }
             (SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
-                SomethingOrNothing::Something(lhs)
+                SomethingOrNothing::new(lhs)
             }
         }
     }
 }
+// ANCHOR_END: minimum_impl
 
 // i32 is Copyable as a very basic type as f32, f64, etc.
 // Arrays for example are not copyable.
+// ANCHOR: minimum_i32
 impl Minimum for i32 {
     fn min(self, rhs: Self) -> Self {
         if self < rhs {
@@ -64,6 +84,7 @@ impl Minimum for i32 {
         }
     }
 }
+// ANCHOR_END: minimum_i32
 
 const SIZE: usize = 9;
 
@@ -73,31 +94,34 @@ fn read_command_line() -> [i32; SIZE] {
 
 // Prints tab and returns tab.
 // Tab would be destructed at the end of the function otherwise.
-fn print_tab(tab: [i32; SIZE]) -> [i32; SIZE] {
+// ANCHOR: print_tab
+fn print_tab<T: std::fmt::Display>(tab: [T; SIZE]) {
     for t in tab {
         print!("{} ", t);
     }
     println!();
-    tab
 }
+// ANCHOR_END: print_tab
 
-fn find_min<T: Minimum>(tab: [T; SIZE]) -> ([T; SIZE], SomethingOrNothing<T>) {
-    let mut min = SomethingOrNothing::Nothing;
+// ANCHOR: find_min
+fn find_min<T: Minimum>(tab: [T; SIZE]) -> SomethingOrNothing<T> {
+    let mut current_minimum = SomethingOrNothing::Nothing;
     // Here is T is not Copyable tab is consumed and cannot be returned
     for t in tab {
-        min = min.min(SomethingOrNothing::Something(t));
+        current_minimum = current_minimum.min(SomethingOrNothing::new(t));
     }
-    (tab, min)
+    current_minimum
 }
+// ANCHOR_END: find_min
 
+// ANCHOR: main
 fn main() {
     let tab = read_command_line();
-
     println!("Among the Somethings in the list:");
-    let tab = print_tab(tab);
-
-    // There are alternatives to access fields of tuples
-    let (_, min) = find_min(tab);
-    // The first field is not used therefore we can replace it with "_"
-    min.print();
+    print_tab(tab);
+    let min = find_min(tab);
+    print(min);
 }
+// ANCHOR_END: main
+
+/* ANCHOR_END: all */
diff --git a/codes/rust_lang/part07/numbers.txt b/codes/rust_lang/part07/numbers.txt
new file mode 100644
index 0000000000000000000000000000000000000000..96c95dafa6dc00eb4f7fb393cdf44412e655b7a3
--- /dev/null
+++ b/codes/rust_lang/part07/numbers.txt
@@ -0,0 +1,5 @@
+3478
+26
+-127
+1287
+189
\ No newline at end of file
diff --git a/codes/rust_lang/part08/src/io.rs b/codes/rust_lang/part08/src/io.rs
index 496c227a0a46ba1cbecd6488b2eede64a61b3e3c..482df9d6e0fa6240028d607a081cb060aed74387 100644
--- a/codes/rust_lang/part08/src/io.rs
+++ b/codes/rust_lang/part08/src/io.rs
@@ -49,7 +49,7 @@ pub fn print_tab(tab: &Vec<i32>) {
 
 /// Prints all the elements of the `tab`.
 /// Tab is borrowed here
-pub fn print_tab_CustomInt(tab: &Vec<CustomInt>) {
+pub fn print_tab_custom_int(tab: &Vec<CustomInt>) {
     for i in tab {
         println!("{i} ");
     }
diff --git a/codes/rust_lang/part08/src/main.rs b/codes/rust_lang/part08/src/main.rs
index 4fd0479b6ab6e773f7552e93276b00b6e1e0623c..1908de7c9f8125639a927f76a5cd61dabf48efe9 100644
--- a/codes/rust_lang/part08/src/main.rs
+++ b/codes/rust_lang/part08/src/main.rs
@@ -7,7 +7,7 @@ fn main() -> Result<(), String> {
         Err(s) => return Err(s),
     };
     println!("Among the custom ints in the list:");
-    io::print_tab_CustomInt(&tab);
+    io::print_tab_custom_int(&tab);
     // There are alternatives to access fields of tuples
     let min = find_min(&tab);
     // The first field is not used therefore we can replace it with "_"