diff --git a/essential_rust.tex b/essential_rust.tex
index 0821077822613dcd328e8285b15a9ef329066a1f..8a65c1f9d10f8d516a5186cbef60968b416991b7 100644
--- a/essential_rust.tex
+++ b/essential_rust.tex
@@ -244,7 +244,7 @@ fn add(x: i32, y: i32) -> i32 {
 \newpage
 
 
-\subsection{Chaînes de caractères}
+\section{Chaînes de caractères}
 
 Les chaînes de caractères en Rust supportent \texttt{UTF-8}, et
 prennent principalement un format parmi :
@@ -446,6 +446,12 @@ fn somme(vect: &Vec<usize>) -> usize {
 }
 \end{lstlisting}
 
+Maintenant que nous avons vu les références nous pouvons voir la forme réelle
+de \texttt{\&[Type]} et \texttt{\&str}. En réalité ce sont des références vers
+des objets de type \texttt{[Type]} et \texttt{str}, mais comme ces objets n'ont
+pas de taille connue on ne peut jamais les stocker sur la pile, donc on y accède
+toujours via une référence.\\
+
 La forme complète d'une référence est \texttt{\&'lft Type} ou \texttt{\&'lft mut Type} :
 voir \Cref{advancedLifetimes} pour plus de détails.
 
@@ -773,14 +779,15 @@ impl User {
 
 \section{Traits}
 
-Les traits sont des ensembles de méthodes que les types sur lesquels ils sont appliqués
-doivent implémenter.
+Les traits sont des ensembles (éventuellement vides) de méthodes regroupées
+sous un nom. Un type ``implémente un trait'' si il a une implémentation de toutes
+les méthodes du trait.
 
-Ils permettent de grouper des objets qui implémentent une fonctionnalité commune,
-et certains donnent accès à des fonctionalités spéciales.
+Les traits permettent de grouper des objets qui implémentent une fonctionnalité
+commune, et certains donnent accès à des fonctionalités spéciales.
 
 Par exemple, pour utiliser \texttt{println!}, il faut que le type implémente
-l'ensemble des méthodes du trait \texttt{std::fmt::Display} pour pouvoir afficher.
+l'ensemble des méthodes du trait \texttt{std::fmt::Display}.
 
 Le trait \texttt{Display} ne contient qu'une seule méthode : \texttt{fmt}.
 
@@ -829,6 +836,8 @@ Voici un aperçu de quelques uns des autres traits les plus fréquents :
 
 \newpage
 
+\subsection{Généricité}
+
 On peut utiliser des traits pour implémenter une seule fois une fonctionalité
 qui ne dépend que de quelques méthodes contenues dans des traits.\\
 
@@ -838,16 +847,14 @@ Cela s'exprime par
 \begin{lstlisting}[style=Rust, language=Rust]
 use std::fmt;
 
-fn afficher_vec<T>(vec: Vec<T>)
-where T: fmt::Display
-{
+fn afficher_vec<T: fmt::Display>(vec: Vec<T>) {
     for elem in vec {
         println!("{elem}");
     }
 }
 
 fn main() {
-    afficher_vec::<usize>(vec![1, 2, 3]);
+    afficher_vec::<usize>(vec![1, 2, 3]);  // Note : ::<Type> n'est souvent pas nécessaire
     afficher_vec::<char>(vec!['a', 'b', 'c']);
     afficher_vec::<&str>(vec!["un", "deux", "trois"]);
 }
@@ -881,6 +888,79 @@ fn main() {
 }
 \end{lstlisting}
 
+\subsection{Traits paramétrés}
+
+On voit parfois des paramètres dans les noms de traits, comme par exemple
+\texttt{Iterator<Item = u8>} ou bien \texttt{From<u8>}.
+
+Le premier indique que en plus des méthodes, le trait \texttt{Iterator} demande
+la définition d'un type à l'intérieur, comme suit :
+
+\begin{lstlisting}[style=Rust, language=Rust]
+impl Iterator for MonType {
+    type Item = u8;
+    ...
+}
+\end{lstlisting}
+Le second signifie que l'implémentation peut dépendre du type d'un paramètre,
+comme nous en verrons un exemple dans \Cref{implFrom}.
+
+\subsection{Implémentations automatiques}
+
+On peut aussi demander d'implémenter un trait automatiquement si un autre
+trait est implémenté.
+
+Par exemple cet exemple tiré de la
+\href{https://doc.rust-lang.org/src/alloc/string.rs.html#2390-2404}{librairie standard}
+indique que le trait \texttt{ToString} est automatiquement implémenté pour tout type
+qui implémente \texttt{Display}.
+
+\begin{lstlisting}[style=Rust, language=Rust]
+impl<T: fmt::Display> ToString for T {
+    fn to_string(&self) -> String {
+        // ici l'implémentation par défaut
+    }
+}
+\end{lstlisting}
+
+Cette utilisation rend particulièrement intéressant le fait d'utiliser les
+traits fournis par la librairie standard, car pour un trait qu'on définit
+explicitement on gagne sans rien faire de plus accès à toutes les fonctionnalités
+qui reposent sur ce trait déjà implémentées par d'autres personnes.
+
+C'est aussi à cela que servent les traits qui ne contiennent aucune méthode.
+Des traits comme \texttt{Copy}, \texttt{Sync}, \texttt{Send}, \texttt{Sized}
+(qui indiquent respectivement que l'objet est facilement duplicable, qu'il est
+possible de l'utiliser depuis plusieurs threads en même temps, qu'il est possible
+de le déplacer d'un thread à un autre, et que sa taille est connue) servent
+de marqueurs et permettent de dire par exemple que notre fonction peut s'appliquer
+à ``n'importe quel type dont on connaît la taille''.
+
+Par exemple voici un conteneur qui contient deux valeurs quelconques et on veut
+exprimer comment en faire une copie.
+\begin{lstlisting}[style=Rust, language=Rust]
+struct Paire<U, V> {
+    u: U,
+    v: V,
+}
+
+impl<U: Clone, V: Clone> Clone for Paire<U, V> {
+    fn clone(&self) -> Self {
+        Paire {
+            u: self.u.clone(),
+            v: self.v.clone(),
+        }
+    }
+}
+// Si on retire les ": Clone" on a une erreur "u et v n'ont pas de méthode Clone"
+// Note: en pratique on n'écrira jamais nous-mêmes le code ci-dessus, car c'est
+// exactement ce qui est généré automatiquement par
+// \#[derive(Clone)]
+// struct Paire<U, V> { ... }
+\end{lstlisting}
+
+
+
 
 
 \section{Gestion des erreurs}
@@ -894,6 +974,8 @@ Rust a deux manières de gérer les erreurs à l'exécution :
 Il est bien sûr facile de convertir une erreur rattrapable en erreur non rattrapable,
 mais l'inverse est par définition impossible.
 
+\subsection{\texttt{panic!}: erreur fatale}
+
 \begin{lstlisting}[style=Rust, language=Rust]
 fn main() {
     let message = "AAAAAAAAAAAAAA";
@@ -927,6 +1009,9 @@ indice trop grand d'un tableau (implémenté par \texttt{index} de
 
 \newpage
 
+\subsection{\texttt{Result} et \texttt{Option}: erreurs non fatales}
+\label{errorHandling}
+
 Pour les erreurs non-fatales, Rust a la structure de donnée suivante :
 
 \begin{lstlisting}[style=Rust, language=Rust]
@@ -941,7 +1026,8 @@ Utilisons cette structure afin de faire un programme pour lire un fichier :
 \begin{lstlisting}[style=Rust, language=Rust]
 use std::fs::File;
 use std::io;
-use std::io::Read;   // Permet d'utiliser la fonction \textbf{read\_to\_string()} du trait Read
+use std::io::Read;  // Permet d'utiliser la fonction \textbf{read\_to\_string()} du trait Read
+                    // (pour savoir pourquoi ce use est nécessaire, consulter \Cref{advancedTraits})
 
 fn main() {
     match read_file() {
@@ -992,7 +1078,199 @@ fn read_file() -> Result<String, io::Error> {
 }
 \end{lstlisting}
 
+\newpage
+\section{Conversions de type}
 
+Les conversions de type en Rust peuvent paraître complexes car il en existe de nombreuses
+variantes.
+
+\subsection{Primitives}
+La conversion entre primitives se fait avec le mot-clé \texttt{as}.
+À part quelques exceptions très restreintes que nous verrons juste après,
+\textit{toutes} les conversions doivent être explicites, même d'un type entier
+à un autre.
+\begin{lstlisting}[style=Rust, language=Rust]
+fn main() {
+    let i: i8 = 5;
+    let u: u8 = i as u8;  // u vaut 5
+
+    // u + i -> erreur: ne peut pas additionner u8 + i8
+    // Il faut faire
+    let i_plus: i8 = u as i8 + i;
+    let u_plus: u8 = u + i as u8;
+
+    let num_a: u8 = 'a' as u8;  // 97
+    let chr_b: char = 98 as char;  // 'b'
+
+    let deux_f: f64 = 2 as f64;  // 2.0
+}
+\end{lstlisting}
+
+\subsection{Traits}
+
+Certains traits signalent la possibilité de faire une conversion vers ou depuis
+un autre type.
+
+\subsubsection{Infaillibles}
+\label{implFrom}
+Les traits \texttt{std::convert::\{From, Into\}} décrivent des conversions
+infaillibles.
+
+Il vaut mieux implémenter uniquement \texttt{From} car \texttt{Into} est
+généré automatiquement en fonction de \texttt{From} si celui-ci existe.
+
+
+\begin{lstlisting}[style=Rust, language=Rust]
+struct Paire<U, V> {
+    u: U,
+    v: V,
+}
+
+impl<U, V> std::convert::From<(U, V)> for Paire<U, V> {
+    fn from((u, v): (U, V)) -> Self {
+        Self { u, v }
+    }
+}
+impl<T> std::convert::From<[T; 2]> for Paire<T, T> {
+    fn from([u, v]: [T; 2]) -> Self {
+        Self { u, v }
+    }
+}
+
+fn main() {
+    let p1: Paire<u8, char> = (1, 'a').into();
+    let p2: Paire<f64, f64> = Paire::from([0.1, 0.2]);
+}
+\end{lstlisting}
+Comme l'illustre cet exemple, on peut avoir des implémentations différentes
+selon un paramètre de type.
+
+
+\subsubsection{Faillibles}
+
+Toutes les conversions ne sont pas garanties de réussir. Si une conversion peut
+échouer on utilise les traits \texttt{std::convert::\{TryFrom, TryInto\}}
+qui sont les équivalents de \texttt{From} et \texttt{Into} avec en plus
+une gestion des erreurs comme introduite dans \Cref{errorHandling}.
+
+\begin{lstlisting}[style=Rust, language=Rust]
+struct U8(u8);
+struct I64(i64);
+
+enum Taille {
+    TropPetit,
+    TropGros,
+}
+
+impl std::convert::TryFrom<I64> for U8 {
+    type Error = Taille;
+    fn try_from(i: I64) -> Result<Self, Self::Error> {
+        if i.0 < 0 {
+            Err(Taille::TropPetit)
+        } else if i.0 > 255 {
+            Err(Taille::TropGros)
+        } else {
+            Ok(Self(i.0 as u8))
+        }
+    }
+}
+
+fn main() {
+    let i_ok: I64 = I64(25);
+    let i_ko: I64 = I64(-3);
+    let u_ok: Result<U8, Taille> = i_ok.try_into();  // Ok(U8(25))
+    let u_ko: Result<U8, Taille> = i_ko.try_into();  // Err(Taille::TropPetit)
+}
+\end{lstlisting}
+
+\subsection{Implicites}
+
+Presque toutes les conversions sont explicites, mais il y a quelques exceptions
+très particulières. Il n'est souvent pas nécessaire d'y réfléchir, et elles
+sont très mineures car elles sont en réalité uniquement des simplifications de notations.
+
+\begin{enumerate}
+    \item perte de mutabilité :\\
+        il y a une conversion automatique de \texttt{\&mut Type} vers \texttt{\&Type}.
+\begin{lstlisting}[style=Rust, language=Rust]
+fn main() {
+    let mut x: u8 = 0;
+    let mutable: &mut u8 = &mut x;
+    let immutable: &u8 = mutable;
+}
+\end{lstlisting}
+        On pourrait se passer de cette conversion car il est possible également d'écrire
+
+        \texttt{let immutable: \&u8 = \&*mutable;}
+\newpage
+
+    \item slices :\\
+        \texttt{\&Vec<Type>} et \texttt{\&[Type; Taille]} sont convertibles en \texttt{\&[Type]}
+\begin{lstlisting}[style=Rust, language=Rust]
+fn main() {
+    let vec: Vec<u8> = vec![0, 1, 2];
+    let arr: [u8; 3] = [0, 1, 2];
+    let vec_ref: &Vec<u8> = &vec;
+    let arr_ref: &[u8; 3] = &arr;
+    let slice_of_vec: &[u8] = vec_ref;
+    let slice_of_arr: &[u8] = arr_ref;
+}
+\end{lstlisting}
+        De la même manière \texttt{\&String} est convertible en \texttt{\&str}.\\
+        Ces conversions sont une notation car elles permettent
+        juste d'écrire \texttt{\&val} au lieu de \texttt{\&val[..]}.
+
+    \item auto-déréférencement :\\
+        l'appel de méthodes peut parfois convertir automatiquement
+        de \texttt{self} vers \texttt{\&self} ou \texttt{\&mut self}
+        ainsi que réciproquement.\\
+\begin{lstlisting}[style=Rust, language=Rust]
+#[derive(Clone, Copy)]  // on reparlera de cette ligne plus tard
+struct Vide();
+impl Vide {
+    fn avec_self(self) {}
+    fn avec_ref(&self) {}
+    fn avec_mut(&mut self) {}
+}
+
+fn main() {
+    let mut v = Vide();
+    // toutes les lignes qui suivent sont équivalentes alors que
+    // pour chaque groupe il n'y en a qu'une seule
+    // qui serait bien typée sans conversions automatiques
+    v.avec_self();
+    v.avec_ref();
+    v.avec_mut();
+    (&v).avec_self();
+    (&v).avec_ref();
+    // (\&v).avec\_mut();  // seule combinaison interdite
+    (&mut v).avec_self();
+    (&mut v).avec_ref();
+    (&mut v).avec_mut();
+
+    // Ce qui suit est possible car Box est un type de
+    // pointeur qui implémente le trait std::ops::Deref
+    let mut b = Box::new(v);
+    b.avec_self();
+    b.avec_ref();
+    b.avec_mut();  // ne serait pas autorisé si b n'était pas mut
+}
+\end{lstlisting}
+        Cette fonctionalité permet d'écrire
+        \texttt{truc.bidule().machin().chose()} plutôt que\\
+        \texttt{(*(\&(\&(*truc).bidule()).machin()).chose()}, le
+        second étant beaucoup moins lisible.
+
+        Ce n'est en revanche pas la raison pour laquelle
+        \texttt{1 + 1} et \texttt{1 + (\&1)} sont toutes les deux
+        des expressions valides. Ici il y a vraiment deux implémentations
+        similaires mais distinctes de \texttt{std::ops::Add}: une pour
+        \texttt{impl Add<u8> for u8} et une pour \texttt{impl Add<\&u8> for u8}.
+
+\end{enumerate}
+
+
+\newpage
 
 \section{Appartenance (\textit{Ownership})}
 \label{ownership}
@@ -1715,6 +1993,10 @@ car ils ont souvent besoin d'avoir accès à des données qui ne sont pas \textt
 
 
 \begin{lstlisting}[style=Rust, language=Rust]
+pub fn add(a: u8, b: u8) -> u8 {
+    a + b
+}
+
 #[cfg(test)]                            // Le bloc qui suit ne sera pas compilé si on n'est
                                         // pas en train de faire des tests
 mod test_add {
@@ -1792,9 +2074,16 @@ On peut la lire avec \texttt{cargo doc --open}
 
 \section{Notions avancées}
 
+Cette section contient des notions qui ne sont pas nécessaires à la
+première lecture.
+
+Il est possible de la survoler pour voir ce qu'elle contient puis d'y revenir
+quand on estime avoir besoin de plus d'informations sur un sujet spécifique.
+
 \subsection{Tout est une expression}
 \label{expressionsEverywhere}
 
+
 \subsection{Newtype}
 \label{patternNewtype}