); // ceci est du Rust valide !
~~~
### Créer ses propres macros
Il peut arriver que l’on soit obligé d’écrire beaucoup de code redondant, du style :
```rust
match entrée_1 {
special_a(x) => { return x; }
_ => {}
}
// ...
match entrée_2 {
special_b(x) => { return x; }
_ => {}
}
```
Le système de macros permet de supprimer le code redondant. Par exemple, le code suivant est équivalent au premier :
```rust
// `macro_rules!` pour indiquer qu’on va créer une macro
// retour_tôt est le nom de la macro qu’on utilisera pour l’appeler
macro_rules! retour_tôt(
($inp:expr $sp:ident) => (
match $inp {
$sp(x) => { return x; }
_ => {}
}
);
)
// ...
retour_tôt!(input_1 special_a);
// ...
retour_tôt!(input_2 special_b);
```
Plus précisément, les macros permettent de générer du code à la compilation. Ainsi, l’exemple ci-dessus va générer les deux fonctions de départ (strictement les mêmes).
Le `$` indique une variable (un peu comme en PHP). Cette syntaxe spéciale permet de différencier le code de la macro et le code Rust en lui-même.
Je ne rentrais pas dans les détails, mais le `($inp:expr $sp:ident)`, c’est comme la définition des arguments d’une fonction, ça indique le « type » de ce qu’on va donner comme argument. Ici, ça indique que `inp` est une expression et `sp` un identifiant de variable (on ne peut donc pas faire n’importe quoi dans les macros).
Mais on peut vraiment faire des choses poussées, plus d’informations sur [la documentation](http://static.rust-lang.org/doc/master/tutorial-macros.html).
# Outils
## Attributs
Les méta-données concernant le code sont passées au compilateur et au générateur de documentation par le biais d’une syntaxe spéciale : les attributs.
```rust
#[test]
// la fonction est un test unitaire (voir plus bas pour les détails)
#[crate_type = "lib"];
// pour compiler en tant que bibliothèque
#[license = "MIT/ASL2"];
// Le point-virgule indique un attribut global
// les autres attributs ne s’appliquent qu’à la déclaration suivante
// cet attribut sert à la documentation et aux paquets (voir plus bas)
#[desc = "Projet Machin"];
#[author = "Jean Dupont"];
// autres attributs pour la documentation
#[cfg(target_os = "linux")]
// la déclaration qui suit est ignorée si le système sur lequel on compile
// n’est pas basé sur Linux.
#[cfg(target_arch = "x86")]
// la même chose, mais concernant l’architecture matérielle
```
## Tests unitaires
Pour écrire des tests unitaires, il suffit de placer `#[test]` sur la ligne précédant une fonction. La fonction ne doit prendre aucun argument et ne rien renvoyer. Si on souhaite que la fonction échoue, il faut mettre en plus `#[should_fail]`.
Les fonctions `check`, `fail`, `assert` (ainsi que `assert_eq`, `assert_approx_eq`, etc) sont très utiles pour les tests unitaires.
```rust
#[test]
fn test_quelques_opérations() {
let x = ~[10];
x.push(5);
x.pop();
}
#[test]
#[should_fail]
fn test_l’échec_hors_des_limites() {
let v: [int] = [];
v[0];
}
```
Il existe un type de tests unitaires un peu spécial : les _benchmarks_ (tests de performances). Il faut utiliser l’attribut `#[bench]` mais aussi un peu plus que ça...
```rust
#[bench]
fn test_trucmuche(b: &mut extra::test::BenchHarness) { // on va utiliser l’argument
// le code de préparation
do b.iter() {
// le code dont vous souhaitez mesurer les performances
}
}
```
De la même façon que le code qu’on compile ou non en fonction de la plateforme, il existe un mécanisme similaire pour les tests unitaires. Il faut utiliser `#[ignore())]`, par exemple `#[ignore(cfg(target_os = "win32"))]`.
Ensuite, il faut utiliser `rustc` avec l’option `--test` :
```
# rustc --test main.rs -o tests
```
Vous pouvez obtenir ça :
```
# ./tests
running 30 tests
running driver::tests::mytest1 ... ok
running driver::tests::mytest2 ... ignored
... snip ...
running driver::tests::mytest30 ... ok
result: ok. 28 passed; 0 failed; 2 ignored
```
Ou ça :
```
# ./test
running 30 tests
running driver::tests::mytest1 ... ok
running driver::tests::mytest2 ... ignored
... snip ...
running driver::tests::mytest30 ... FAILED
result: FAILED. 27 passed; 1 failed; 2 ignored
```
Il est possible de placer les tests dans un module et de n’exécuter que ceux-ci :
```
# ./tests mytest1
running 11 tests
running driver::tests::mytest1 ... ok
running driver::tests::mytest10 ... ignored
... snip ...
running driver::tests::mytest19 ... ok
result: ok. 11 passed; 0 failed; 1 ignored
```
Pour les tests de performance :
```
# ./tests --bench
running 2 tests
test bench_sum_1024_ints ... bench: 709 ns/iter (+/- 82)
test initialise_a_vector ... bench: 424 ns/iter (+/- 99) = 19320 MB/s
test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
```
## rustdoc
`rustdoc` est un outil livré avec Rust qui permet de générer de la documentation à partir des commentaires du code.
Pour qu’un commentaire soit considéré comme de la documentation, il faut utiliser une syntaxe spéciale :
```rust
/// Ceci est un commentaire de documentation mono-ligne
/**
* Ceci est un commentaire de documentation
* sur plusieurs lignes
*/
```
La syntaxe utilisée pour la mise en forme est le Markdown (comme sur Linuxfr), et la version HTML est générée avec Pandoc.
Il y a quelques règles cependant :
* La première phrase d’un commentaire sera prise comme résumé de la suite du commentaire
* Seuls les titres indiqués avec un seul `#` (et non plusieurs `#` ou plusieurs `=` en dessous du texte) sont interprétés par `rustdoc`. Cette règle sera assouplie dans le futur.
Il y a également quelques conventions :
La première phrase doit décrire succinctement ce que l’élément fait. Si ça n’est pas suffisant, la suite devra décrire quoi et pourquoi l’élément fait ce qu’il fait, les entrées-sorties, et mentionner sous quelles conditions le code va échouer.
On doit utiliser des titres standards quand le texte devient long : « Arguments », « Return value » (valeur renvoyée), « Failure » (échec), « Example », « Safety notes » (notes sur la sûreté), et « Performance notes » (notes sur la performance). Les arguments doivent être écrit de la façon suivante :
```markdown
# Arguments
* `arg1` - pour faire tel truc
* `arg2` - pour connaitre telle chose
```
Enfin, pour écrire du code, on utilise la syntaxe suivante :
~~~
Mettez votre code ici
~~~
Les autres façons d’écrire du code en Markdown ne fonctionnent pas (```) ou sont ambigües (quatre espaces devant le code) et peuvent donc ne pas fonctionner.
Pour générer la documentation, rien de plus simple : il suffit d’ajouter `#[link(name = "Nom de votre projet")]` en en-tête de votre fichier `main.rs` (ou le fichier principal de votre projet) et d’utiliser la commande `rustdoc main.rs`. Cela vous donnera une documentation au format HTML.
Mais on peut fournir bien plus d’informations... Je vous laisse jeter un coup d’œil à la configuration utilisée dans la bibliothèque standard de Rust :
```rust
#[link(name = "std",
vers = "0.9-pre",
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
url = "https://github.com/mozilla/rust/tree/master/src/libstd")];
#[comment = "The Rust standard library"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://static.rust-lang.org/doc/master")];
```
Note : en réalité, la syntaxe de documentation n’est que du sucre syntaxique pour dire `#[doc = "Description blablabla"]`.
## rustpkg
[rustpkg](http://static.rust-lang.org/doc/master/rustpkg.html) est un outil qui permet de faire des paquets Rust, largement inspiré du [gestionnaire de paquets de Go](http://golang.org/cmd/go/). On peut donner des informations à cet outil grâce aux attributs (par exemple, `#[licence = "ma_licence"]` et `#[link(vers = "mon_numéro_de_version")]`).
Un espace de travail valide contient les dossiers suivants :
* src/, qui contient un dossier par paquet (ex : src/foo/main.rs) ;
* lib/, `rustpkg install` va y installer les bibliothèques nécessaires dans un sous-dossier (ex : si libbar est nécessaire à foo, alors elle sera installée à lib/x86_64-apple-darwin/libbar-[hash].dylib) ;
* bin/, pour les exécutables (ex : bin/foo) ;
* build/, `rustpkg build` va y stocker les fichiers temporaires de compilation (ex : build/x86_64-apple-darwin/foo/main.o).
L’ID d’un paquet prend la forme d’une URL (par exemple, github.com/mozilla/rust si c’est un dépôt distant ou /foo/bar/ si c’est un dépôt local). Une version peut être précisée :
* Un tag (ex : github.com/mozilla/rust#0.3). Dans ce cas, rustpkg va vérifier que le dépôt contient bien un tag nommé 0.3 ;
* Une révision particulière (ex : github.com/mozilla/rust#release-0.7). Comme ça n’est pas un nombre décimal, rustpkg passe la _refspec_ (ce qu’il y a après le `#`) au système de gestion de version sans l’interpréter. Cela compte comme un ID de paquet à part entière, là où une nouvelle version peut satisfaire la dépendance envers une ancienne version ;
* Une révision particulière (ex : github.com/mozilla/rust#5c4cd30f80). La _refspec est également passée directement au système de gestion de version.
Une fois bien paramétré, on a accès aux commandes `rustpkg build`, `rustpkg clean`, `rustpkg install`, et `rustpkg test`. Autant dire que ça automatise pas mal de choses !
# L’état actuel du projet
## Gros travaux avant la 1.0
La version 1 du langage arrive à grands pas, et il reste pas mal de travail. Côté développeur, la syntaxe ne change presque pas mais à chaque version il y a des incompatibilités, heureusement très souvent mineures.
Les développements se focalisent sur les corrections de bugs, l’organisation et le nettoyage du code, mais aussi compléter la bibliothèque standard et améliorer les performances.
Cependant il y a aussi un énorme travail à faire sur la documentation, qui, bien que très complète, nécessite plus d’efforts de mise en page. Les tutoriels nécessitent quant à eux beaucoup plus de travail pour les rendre plus accessibles, complets et simples.
## Tester (ou faire des trucs sérieux avec) Rust
Pour l’instant, le seul moyen de tester Rust est d’utiliser l’exécutable de la version 0.8 pour Windows, ou de compiler, au choix, la version 0.8 ou la version en cours de développement (conseillée si vous démarrez un projet un peu important en Rust) pour MacOS.
Si vous êtes sous Ubuntu, vous pouvez ajouter un [PPA qui fournit plusieurs versions de Rust dont des nightlies](https://launchpad.net/~hansjorg/+archive/rust).
Pour Arch Linux, Rust a récemment intégré le dépôt `[community]`. De plus, un des développeurs de Rust a mis en place un dépôt contenant les compilations quotidiennes de la version de développement. Il suffit d’ajouter :
```bash
[thestinger]
SigLevel = Optional
Server = http://pkgbuild.com/~thestinger/repo/$arch
```
à votre `/etc/pacman.conf` et d’installer le paquet `rust-git`.
Il est aussi possible dans Gentoo de rajouter le paquet en version 0.8 et développement en utilisant l'overlay `rust` (ajouter `dev-lang/rust` dans `/etc/portage/packages.keywords`) :
```
layman -a rust
emerge =dev-lang/rust-0.8
```
### Environnements de développement
#### Coloration syntaxique
Des configurations pour la coloration syntaxique et l’indentation sont disponibles pour Vim, Emacs, Sublime Text 2 et Kate. Il y a aussi un support pour ctags, Eclipse, [NetBeans](https://github.com/drrb/rust-netbeans) et [autres](https://github.com/mozilla/rust/wiki/Doc-packages%2C-editors%2C-and-other-tools#editors).
#### Débugueur
On peut également noter qu’il est possible de [configurer Eclipse (ou d’autres IDE) pour débuguer du code Rust](http://michaelwoerister.github.io/2013/09/27/what-you-call-the-present.html) via [GDB](http://www.gnu.org/software/gdb/) et [LLDB](http://lldb.llvm.org/).
## Projets basés sur Rust
Dans cette partie, je vais vous présenter rapidement une sélection de projets réalisés en Rust, déjà parce qu’il y a beaucoup trop de projets différents et d’autre part parce que tous les projets ne sont pas forcément intéressants ou utilisables. Et j’ai d’autres choses à faire dans la vie aussi. :p
### Logiciels
Un certain nombre de logiciels bas niveau ont été créés en Rust, démontrant la polyvalence du langage et l’intérêt du langage dans ce domaine. Plusieurs personnes se sont montrées intéressées dans le remplacement du C par le Rust pour le bas niveau, dans le domaine de l’embarqué par exemple. Il y a aussi quelques jeux vidéo en cours de développement (notamment un émulateur NES) ainsi qu’un traqueur de bug.
[zero.rs](https://github.com/pcwalton/zero.rs) est un projet de moins de 300 lignes qui permet de lancer des programmes Rust sans système d’exploitation. Nécessite seulement l’accès à quelques fonctions C de base (les tâches, les [échecs](http://static.rust-lang.org/doc/master/tutorial-conditions.html#failure) et le ramasse-miettes ne fonctionnent pas).
Deux projets utilisent zero.rs : [Rust.ko](https://github.com/tsgates/rust.ko), un module minimal pour le noyau Linux et [rustboot](https://github.com/charliesome/rustboot), un système d’exploitation dont la seule fonctionnalité est de peindre l’écran en rouge — ce qui a beaucoup intéressé les développeurs de GNOME.
Nous avons également [sprocketnes](https://github.com/pcwalton/sprocketnes), un émulateur NES qui sert de preuve de concept, ne vous attendez pas à ce que vos jeux fonctionnent parfaitement dessus. C’est le genre de programme qui devrait fonctionner avec zero.rs.
Enfin, [Evict-BT](https://github.com/singingboyo/evict) est un système de suivi de bugs.
### Bibliothèques et bindings généralistes
Toujours dans une volonté de ne pas réinventer la roue (ou par flemme ?), on trouve des [bindings](http://fr.wikipedia.org/wiki/Binding#Binding_de_langage) à la pelle mais peu de bibliothèques en Rust.
Dans les bindings, on a [SQLite3](https://github.com/linuxfood/rustsqlite), [PostGreSQL](https://github.com/sfackler/rust-postgres), [MongoDB](https://github.com/10gen-interns/mongo-rust-driver-prototype), (écrit par les développeurs de MongoDB eux-mêmes !), [Cocoa](https://github.com/mozilla-servo/rust-cocoa) (le framework objet de Mac OS X), [wxWidgets](https://github.com/kenz-gelsoft/wxRust) (bibliothèque d’interface graphique basée sur GTK), [PCRE](https://github.com/uasi/rust-pcre) (_Perl Compatible Regular Expression_, expressions régulières compatibles Perl), [libpng](https://github.com/mozilla-servo/rust-png), [OpenCL](https://github.com/luqmana/rust-opencl), etc.
J’ai trouvé deux bibliothèques Rust intéressantes : [RustyMem](https://github.com/williamw520/rustymem), bibliothèque client pour se connecter à un serveur Memcached et [RustyXML](https://github.com/Florob/RustyXML), un parseur XML qui fournit une API de type SAX.
### Jeux vidéos
L’intérêt de la communauté autour du langage Rust pour faire des jeux vidéo justifie à lui tout seul cette partie ! Il y a déjà pas mal de ressources, et le Rust risque d’être très intéressant dans ce domaine...
Il y a des bindings pour [SDL1](https://github.com/brson/rust-sdl), [SDL2](https://github.com/AngryLawyer/rust-sdl2), [SFML2](https://github.com/JeremyLetang/rust-sfml), [Allegro5](https://github.com/SiegeLord/RustAllegro), etc. On peut aussi faire de l’[OpenGL](https://github.com/bjz/gl-rs), on peut utiliser [OpenAL](https://github.com/bjz/openal-rs/) et [PortAudio](https://github.com/JeremyLetang/rust-portaudio).
On a bien sûr quelques bibliothèques Rust, comme [kiss3d](https://github.com/sebcrozet/kiss3d) (moteur graphique 3D simple et stupide — KISS), [nphysics](https://github.com/sebcrozet/nphysics) (moteur physique temps réel de corps rigides 2 et 3D), [cgmath-rs](https://github.com/bjz/cgmath-rs) et [nalgebra](https://github.com/sebcrozet/nalgebra) (mathématiques pour les graphismes et la physique temps réel).
Et bien sûr on a des jeux ! On a deux projets de rogue-like, deux moteurs de FPS en développement, un projet de jeu de rôle en 3D, et un jeu de rythme qui est une traduction quasi-directe du C vers le Rust.
Mais je perds mon temps alors que tout cela est mis à jour régulièrement sur le [wiki](https://github.com/mozilla/rust/wiki/Computer-Graphics-and-Game-Development) !
## Quel avenir pour Rust ?
Le langage D, bien que très prometteur, n’a jamais percé. Pourquoi en serait-il autrement avec le Rust ?
Le langage D, c’est un compilateur officiel au frontal non-libre, qui avait des fuites de mémoire et un développement fermé (au départ, ça se passe sur Github maintenant), une communauté qui dès ses débuts s’est scindée pour développer deux bibliothèques standard incompatibles et un langage dont l’intérêt ne saute pas aux yeux car similaire au C++ à première vue.
Comme vous pouvez le déduire des projets ci-dessus, la communauté derrière Rust est très active. Et c’est sans doute le plus gros point fort du langage pour lui permettre de percer, de décoller rapidement et de ne pas s’essouffler comme le D.
Le développement du langage se déroule entièrement sur Github, au moins 25 commits par jour tous les jours (des fois ça peut atteindre 50 !), des projets sérieux qui se basent sur le langage avec Mozilla derrière, des tas de projets fun aussi, et des dizaines de bindings... Et un langage aussi bon techniquement, sinon meilleur que le D.
En conclusion, même si on parle assez peu de Rust, il est beaucoup plus connu que le D ne l’était au même stade de développement. De plus, il a vraiment beaucoup d’atouts de son côté : exploitation de fonctionnalités peu connues mais qui existent déjà dans un autre langage (pas d’inconnues et d’expérimentations), haut et bas niveau, beaucoup de vérifications à la compilation, une communauté pour le moment restreinte mais active (avec beaucoup de petits projets mais aussi Servo), etc.
Reste à savoir s’il saura s’imposer dans son domaine de prédilection grâce à sa sûreté (face à C, C++) ou ailleurs grâce à sa vitesse (Java, PHP, Python, Ruby...), car les langages actuels sont très implantés.
## La communauté Rust
Il y a déjà quelques endroits où l’on peut discuter du Rust : le [sous-Reddit r/rust](http://www.reddit.com/r/rust/), la [liste de diffusion](https://mail.mozilla.org/listinfo/rust-dev) et les canaux IRC (_what else?_) `#rust` et `#rust-gamedev` sur [irc.mozilla.org](https://wiki.mozilla.org/IRC). Ce sont des canaux très actifs, les personnes présentes sont très sympas et se feront une joie de vous aider. Il y a aussi les canaux `#rust-internals` et `#servo` pour les développeurs.
Bref, tout cela ne vous dispense pas d’aller [lire le putain de manuel](http://fr.wikipedia.org/wiki/RTFM_%28expression%29) (que vous trouverez sur le site de Rust) !
## Contribuer
* faire connaitre le projet ;
* traduire le tutoriel et la documentation de Rust en français. [J’ai commencé à traduire le tutoriel en français](https://github.com/sinma/rust) ;
* écrire un binding pour pouvoir utiliser une bibliothèque sympa depuis Rust ;
* réaliser un projet codé en Rust ;
* [écrire du code](https://github.com/mozilla/rust/wiki/Note-guide-for-new-contributors) : compilateur, bibliothèque standard ou outils du projet.
# Conclusion
C’est un langage moderne, lisible, performant. Et surtout, il semble avoir un avenir prometteur.
Mais le mieux, c’est de tester par soi-même !