mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-10 13:35:08 +00:00
Imported Upstream version 1.0.0~beta.3
This commit is contained in:
parent
c34b17963d
commit
9346a6ac1c
96
AUTHORS.txt
96
AUTHORS.txt
@ -9,17 +9,19 @@ Aaron Todd <github@opprobrio.us>
|
||||
Aaron Turon <aturon@mozilla.com>
|
||||
Aaron Weiss <aaronweiss74@gmail.com>
|
||||
Adam Bozanich <adam.boz@gmail.com>
|
||||
Adam Jacob <adam@opscode.com>
|
||||
Adam Roben <adam@roben.org>
|
||||
Adam Szkoda <adaszko@gmail.com>
|
||||
Adenilson Cavalcanti <cavalcantii@gmail.com>
|
||||
Adolfo Ochagavía <aochagavia92@gmail.com>
|
||||
Adrien Brault <adrien.brault@gmail.com>
|
||||
Adrien Tétar <adri-from-59@hotmail.fr>
|
||||
Ahmed Charles <acharles@outlook.com>
|
||||
Ahmed Charles <ahmedcharles@gmail.com>
|
||||
Aidan Cully <github@aidan.users.panix.com>
|
||||
Aidan Hobson Sayers <aidanhs@cantab.net>
|
||||
Akos Kiss <akiss@inf.u-szeged.hu>
|
||||
Alan Andrade <alan.andradec@gmail.com>
|
||||
Alan Cutter <alancutter@chromium.org>
|
||||
Alan Williams <mralert@gmail.com>
|
||||
Aleksander Balicki <balicki.aleksander@gmail.com>
|
||||
Aleksandr Koshlo <sash7ko@gmail.com>
|
||||
@ -29,6 +31,8 @@ Alex Lyon <arcterus@mail.com>
|
||||
Alex Rønne Petersen <alex@lycus.org>
|
||||
Alex Whitney <aw1209@ic.ac.uk>
|
||||
Alexander Bliskovsky <alexander.bliskovsky@gmail.com>
|
||||
Alexander Campbell <alexanderhcampbell@gmail.com>
|
||||
Alexander Chernyakhovsky <achernya@mit.edu>
|
||||
Alexander Korolkov <alexander.korolkov@gmail.com>
|
||||
Alexander Light <allight@cs.brown.edu>
|
||||
Alexander Stavonin <a.stavonin@gmail.com>
|
||||
@ -41,6 +45,7 @@ Alfie John <alfiej@fastmail.fm>
|
||||
Ali Smesseim <smesseim.ali@gmail.com>
|
||||
Alisdair Owens <awo101@zepler.net>
|
||||
Aljaž "g5pw" Srebrnič <a2piratesoft@gmail.com>
|
||||
Amol Mundayoor <amol.com@gmail.com>
|
||||
Amy Unger <amy.e.unger@gmail.com>
|
||||
Anders Kaseorg <andersk@mit.edu>
|
||||
Andre Arko <andre@arko.net>
|
||||
@ -56,6 +61,7 @@ Andrew Cann <shum@canndrew.org>
|
||||
Andrew Chin <achin@eminence32.net>
|
||||
Andrew Dunham <andrew@du.nham.ca>
|
||||
Andrew Gallant <jamslam@gmail.com>
|
||||
Andrew Hobden <andrew@hoverbear.org>
|
||||
Andrew Paseltiner <apaseltiner@gmail.com>
|
||||
Andrew Poelstra <asp11@sfu.ca>
|
||||
Andrew Wagner <drewm1980@gmail.com>
|
||||
@ -110,6 +116,8 @@ Brendan McLoughlin <btmcloughlin@gmail.com>
|
||||
Brendan Zabarauskas <bjzaba@yahoo.com.au>
|
||||
Brett Cannon <brett@python.org>
|
||||
Brian Anderson <banderson@mozilla.com>
|
||||
Brian Brooks <brooks.brian@gmail.com>
|
||||
Brian Campbell <lambda@continuation.org>
|
||||
Brian Dawn <brian.t.dawn@gmail.com>
|
||||
Brian J Brennan <brianloveswords@gmail.com>
|
||||
Brian J. Burg <burg@cs.washington.edu>
|
||||
@ -122,6 +130,8 @@ Cadence Marseille <cadencemarseille@gmail.com>
|
||||
Caitlin Potter <snowball@defpixel.com>
|
||||
Cam Jackson <camjackson89@gmail.com>
|
||||
Cameron Zwarich <zwarich@mozilla.com>
|
||||
Camille Roussel <camille@rousselfamily.com>
|
||||
Camille TJHOA <camille.tjhoa@outlook.com>
|
||||
CarVac <c.lo.to.da.down.lo@gmail.com>
|
||||
Carl Lerche <me@carllerche.com>
|
||||
Carl-Anton Ingmarsson <mail@carlanton.se>
|
||||
@ -132,6 +142,8 @@ Carter Hinsley <carterhinsley@gmail.com>
|
||||
Carter Tazio Schonwald <carter.schonwald@gmail.com>
|
||||
Caspar Krieger <caspar@asparck.com>
|
||||
Chase Southwood <chase.southwood@gmail.com>
|
||||
Ches Martin <ches@whiskeyandgrits.net>
|
||||
Chloe <5paceToast@users.noreply.github.com>
|
||||
Chris Double <chris.double@double.co.nz>
|
||||
Chris Morgan <me@chrismorgan.info>
|
||||
Chris Nixon <chris.nixon@sigma.me.uk>
|
||||
@ -158,7 +170,9 @@ Corey Farwell <coreyf+rust@rwell.org>
|
||||
Corey Ford <corey@coreyford.name>
|
||||
Corey Richardson <corey@octayn.net>
|
||||
Cristi Burcă <scribu@gmail.com>
|
||||
Cristian Kubis <cristian.kubis@tsunix.de>
|
||||
DJUrsus <colinvh@divitu.com>
|
||||
Dabo Ross <daboross@daboross.net>
|
||||
Damian Gryski <damian@gryski.com>
|
||||
Damien Grassart <damien@grassart.com>
|
||||
Damien Radtke <dradtke@channeliq.com>
|
||||
@ -167,6 +181,8 @@ Dan Albert <danalbert@google.com>
|
||||
Dan Burkert <dan@danburkert.com>
|
||||
Dan Connolly <dckc@madmode.com>
|
||||
Dan Luu <danluu@gmail.com>
|
||||
Dan Schatzberg <schatzberg.dan@gmail.com>
|
||||
Dan W. <1danwade@gmail.com>
|
||||
Dan Yang <dsyang@fb.com>
|
||||
Daniel Brooks <db48x@db48x.net>
|
||||
Daniel Fagnan <dnfagnan@gmail.com>
|
||||
@ -174,6 +190,7 @@ Daniel Farina <daniel@fdr.io>
|
||||
Daniel Griffen <daniel@dgriffen.com>
|
||||
Daniel Grunwald <daniel@danielgrunwald.de>
|
||||
Daniel Hofstetter <daniel.hofstetter@42dh.com>
|
||||
Daniel Lobato García <elobatocs@gmail.com>
|
||||
Daniel Luz <dev@mernen.com>
|
||||
Daniel MacDougall <dmacdougall@gmail.com>
|
||||
Daniel Micay <danielmicay@gmail.com>
|
||||
@ -183,17 +200,23 @@ Daniel Ralston <Wubbulous@gmail.com>
|
||||
Daniel Rosenwasser <DanielRosenwasser@gmail.com>
|
||||
Daniel Ursache Dogariu <contact@danniel.net>
|
||||
Daniil Smirnov <danslapman@gmail.com>
|
||||
Darin Morrison <darinmorrison+git@gmail.com>
|
||||
Darrell Hamilton <darrell.noice@gmail.com>
|
||||
Dave Herman <dherman@mozilla.com>
|
||||
Dave Hodder <dmh@dmh.org.uk>
|
||||
Dave Huseby <dhuseby@mozilla.com>
|
||||
David Creswick <dcrewi@gyrae.net>
|
||||
David Forsythe <dforsythe@gmail.com>
|
||||
David Halperin <halperin.dr@gmail.com>
|
||||
David King <dave@davbo.org>
|
||||
David Klein <david.klein@baesystemsdetica.com>
|
||||
David Mally <djmally@gmail.com>
|
||||
David Manescu <david.manescu@gmail.com>
|
||||
David Rajchenbach-Teller <dteller@mozilla.com>
|
||||
David Renshaw <dwrenshaw@gmail.com>
|
||||
David Vazgenovich Shakaryan <dvshakaryan@gmail.com>
|
||||
Davis Silverman <sinistersnare@gmail.com>
|
||||
Denis Defreyne <denis.defreyne@stoneship.org>
|
||||
Derecho <derecho@sector5d.org>
|
||||
Derek Chiang <derekchiang93@gmail.com>
|
||||
Derek Guenther <dguenther9@gmail.com>
|
||||
@ -214,10 +237,12 @@ Do Nhat Minh <mrordinaire@gmail.com>
|
||||
Dominik Inführ <dominik.infuehr@gmail.com>
|
||||
Donovan Preston <donovanpreston@gmail.com>
|
||||
Douglas Young <rcxdude@gmail.com>
|
||||
Drew Crawford <drew@sealedabstract.com>
|
||||
Drew Willcoxon <adw@mozilla.com>
|
||||
Duane Edwards <mail@duaneedwards.net>
|
||||
Duncan Regan <duncanregan@gmail.com>
|
||||
Dylan Braithwaite <dylanbraithwaite1@gmail.com>
|
||||
Dylan Ede <dylanede@googlemail.com>
|
||||
Dzmitry Malyshau <kvarkus@gmail.com>
|
||||
Earl St Sauver <estsauver@gmail.com>
|
||||
Eduard Bopp <eduard.bopp@aepsil0n.de>
|
||||
@ -230,12 +255,14 @@ Elantsev Serj <elantsev@yandex-team.ru>
|
||||
Elliott Slaughter <elliottslaughter@gmail.com>
|
||||
Elly Fong-Jones <elly@leptoquark.net>
|
||||
Emanuel Rylke <ema-fox@web.de>
|
||||
Emeliov Dmitrii <demelev1990@gmail.com>
|
||||
Eric Allen <ericpallen@gmail.com>
|
||||
Eric Biggers <ebiggers3@gmail.com>
|
||||
Eric Holk <eric.holk@gmail.com>
|
||||
Eric Holmes <eric@ejholmes.net>
|
||||
Eric Kidd <git@randomhacks.net>
|
||||
Eric Martin <e.a.martin1337@gmail.com>
|
||||
Eric Platon <eric.platon@waku-waku.ne.jp>
|
||||
Eric Reed <ecreed@cs.washington.edu>
|
||||
Erick Rivas <chemical.rivas@gmail.com>
|
||||
Erick Tryzelaar <erick.tryzelaar@gmail.com>
|
||||
@ -268,6 +295,7 @@ Florian Wilkens <floya@live.de>
|
||||
Florian Zeitz <florob@babelmonkeys.de>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Franklin Chen <franklinchen@franklinchen.com>
|
||||
FuGangqiang <fu_gangqiang@163.com>
|
||||
Gabriel <g2p.code@gmail.com>
|
||||
Gareth Daniel Smith <garethdanielsmith@gmail.com>
|
||||
Garrett Heel <garrettheel@gmail.com>
|
||||
@ -279,8 +307,10 @@ Geoffrey Thomas <geofft@ldpreload.com>
|
||||
Geoffroy Couprie <geo.couprie@gmail.com>
|
||||
George Papanikolaou <g3orge.app@gmail.com>
|
||||
Georges Dubus <georges.dubus@gmail.com>
|
||||
Germano Gabbianelli <tyrion@users.noreply.github.com>
|
||||
Gil Cottle <rc@redtown.org>
|
||||
Gioele Barabucci <gioele@svario.it>
|
||||
GlacJAY <glacjay@gmail.com>
|
||||
Gleb Kozyrev <gleb@gkoz.com>
|
||||
Glenn Willen <gwillen@nerdnet.org>
|
||||
Gonçalo Cabrita <_@gmcabrita.com>
|
||||
@ -303,9 +333,11 @@ Herman J. Radtke III <hermanradtke@gmail.com>
|
||||
HeroesGrave <heroesgrave@gmail.com>
|
||||
Hong Chulju <ang0123dev@gmail.com>
|
||||
Honza Strnad <hanny.strnad@gmail.com>
|
||||
Huachao Huang <huachao.huang@gmail.com>
|
||||
Hugo Jobling <hello@thisishugo.com>
|
||||
Hugo van der Wijst <hugo@wij.st>
|
||||
Huon Wilson <dbau.pp+github@gmail.com>
|
||||
Hyeon Kim <simnalamburt@gmail.com>
|
||||
Ian Connolly <iconnolly@mozilla.com>
|
||||
Ian D. Bollinger <ian.bollinger@gmail.com>
|
||||
Ian Daniher <it.daniher@gmail.com>
|
||||
@ -318,12 +350,14 @@ Isaac Aggrey <isaac.aggrey@gmail.com>
|
||||
Isaac Dupree <antispam@idupree.com>
|
||||
Ivan Enderlin <ivan.enderlin@hoa-project.net>
|
||||
Ivan Petkov <ivanppetkov@gmail.com>
|
||||
Ivan Radanov Ivanov <ivanradanov@yahoo.co.uk>
|
||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Ivano Coppola <rgbfirefox@gmail.com>
|
||||
J. J. Weber <jjweber@gmail.com>
|
||||
J.C. Moyer <jmoyer1992@gmail.com>
|
||||
JONNALAGADDA Srinivas <js@ojuslabs.com>
|
||||
JP Sugarbroad <jpsugar@google.com>
|
||||
JP-Ellis <coujellis@gmail.com>
|
||||
Jack Heizer <jack.heizer@gmail.com>
|
||||
Jack Moffitt <jack@metajack.im>
|
||||
Jacob Edelman <edelman.jd@gmail.com>
|
||||
@ -338,6 +372,7 @@ Jake Kerr <kodafox@gmail.com>
|
||||
Jake Scott <jake.net@gmail.com>
|
||||
Jakub Bukaj <jakub@jakub.cc>
|
||||
Jakub Wieczorek <jakubw@jakubw.net>
|
||||
Jakub Vrána <jakub@vrana.cz>
|
||||
James Deng <cnjamesdeng@gmail.com>
|
||||
James Hurst <jamesrhurst@users.noreply.github.com>
|
||||
James Lal <james@lightsofapollo.com>
|
||||
@ -359,6 +394,7 @@ Jason Toffaletti <jason@topsy.com>
|
||||
Jauhien Piatlicki <jauhien@gentoo.org>
|
||||
Jay Anderson <jayanderson0@gmail.com>
|
||||
Jay True <glacjay@gmail.com>
|
||||
Jeaye <jeaye@arrownext.com>
|
||||
Jed Davis <jld@panix.com>
|
||||
Jed Estep <aje@jhu.edu>
|
||||
Jeff Balogh <jbalogh@mozilla.com>
|
||||
@ -375,29 +411,36 @@ Jesse Jones <jesse9jones@gmail.com>
|
||||
Jesse Luehrs <doy@tozt.net>
|
||||
Jesse Ray <jesse@localhost.localdomain>
|
||||
Jesse Ruderman <jruderman@gmail.com>
|
||||
Jihyun Yu <jihyun@nclab.kaist.ac.kr>
|
||||
Jessy Diamond Exum <jessy.diamondman@gmail.com>
|
||||
Jihyeok Seo <me@limeburst.net>
|
||||
Jihyun Yu <j.yu@navercorp.com>
|
||||
Jim Apple <jbapple+rust@google.com>
|
||||
Jim Blandy <jimb@red-bean.com>
|
||||
Jim Radford <radford@blackbean.org>
|
||||
Jimmie Elvenmark <flugsio@gmail.com>
|
||||
Jimmy Lu <jimmy.lu.2011@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jiří Stránský <jistr@jistr.com>
|
||||
Joe Pletcher <joepletcher@gmail.com>
|
||||
Joe Schafer <joe@jschaf.com>
|
||||
Johannes Hoff <johshoff@gmail.com>
|
||||
Johannes Löthberg <johannes@kyriasis.com>
|
||||
Johannes Muenzel <jmuenzel@gmail.com>
|
||||
Johannes Oertel <johannes.oertel@uni-due.de>
|
||||
John Albietz <inthecloud247@gmail.com>
|
||||
John Barker <jebarker@gmail.com>
|
||||
John Clements <clements@racket-lang.org>
|
||||
John Ericson <Ericson2314@Yahoo.com>
|
||||
John Fresco <john.fresco@utah.edu>
|
||||
John Gallagher <jgallagher@bignerdranch.com>
|
||||
John Hodge <acessdev@gmail.com>
|
||||
John Kåre Alsaker <john.kare.alsaker@gmail.com>
|
||||
John Kleint <jk@hinge.co>
|
||||
John Kåre Alsaker <john.kare.alsaker@gmail.com>
|
||||
John Louis Walker <injyuw@gmail.com>
|
||||
John Schmidt <john.schmidt.h@gmail.com>
|
||||
John Simon <john@johnsoft.com>
|
||||
John Zhang <john@zhang.io>
|
||||
Jon Haddad <jon@jonhaddad.com>
|
||||
Jon Morton <jonanin@gmail.com>
|
||||
Jonas Hietala <tradet.h@gmail.com>
|
||||
@ -407,6 +450,7 @@ Jonathan Reem <jonathan.reem@gmail.com>
|
||||
Jonathan S <gereeter@gmail.com>
|
||||
Jonathan Sternberg <jonathansternberg@gmail.com>
|
||||
Joonas Javanainen <joonas.javanainen@gmail.com>
|
||||
Jordan Woehr <jordanwoehr@gmail.com>
|
||||
Jordi Boggiano <j.boggiano@seld.be>
|
||||
Jorge Aparicio <japaricious@gmail.com>
|
||||
Jorge Israel Peña <jorge.israel.p@gmail.com>
|
||||
@ -423,16 +467,17 @@ Joshua Wise <joshua@joshuawise.com>
|
||||
Joshua Yanovski <pythonesque@gmail.com>
|
||||
Julia Evans <julia@jvns.ca>
|
||||
Julian Orth <ju.orth@gmail.com>
|
||||
Julian Viereck <julian.viereck@gmail.com>
|
||||
Junseok Lee <lee.junseok@berkeley.edu>
|
||||
Junyoung Cho <june0.cho@samsung.com>
|
||||
JustAPerson <jpriest8@ymail.com>
|
||||
Justin Noah <justinnoah@gmail.com>
|
||||
Jyun-Yan You <jyyou.tw@gmail.com>
|
||||
Kang Seonghoon <kang.seonghoon@mearie.org>
|
||||
Kang Seonghoon <public+git@mearie.org>
|
||||
Kasey Carrothers <kaseyc.808@gmail.com>
|
||||
Keegan McAllister <mcallister.keegan@gmail.com>
|
||||
Kelly Wilson <wilsonk@cpsc.ucalgary.ca>
|
||||
Kelvin Ly <kelvin.ly1618@gmail.com>
|
||||
Ken Tossell <ken@tossell.net>
|
||||
KernelJ <kernelj@epixxware.com>
|
||||
Keshav Kini <keshav.kini@gmail.com>
|
||||
@ -442,6 +487,7 @@ Kevin Butler <haqkrs@gmail.com>
|
||||
Kevin Cantu <me@kevincantu.org>
|
||||
Kevin Mehall <km@kevinmehall.net>
|
||||
Kevin Murphy <kemurphy.cmu@gmail.com>
|
||||
Kevin Rauwolf <sweetpea-git@tentacle.net>
|
||||
Kevin Walter <kevin.walter.private@googlemail.com>
|
||||
Kevin Yap <me@kevinyap.ca>
|
||||
Kiet Tran <ktt3ja@gmail.com>
|
||||
@ -459,6 +505,8 @@ Lee Wondong <wdlee91@gmail.com>
|
||||
LemmingAvalanche <haugsbakk@yahoo.no>
|
||||
Lennart Kudling <github@kudling.de>
|
||||
Leo Testard <leo.testard@gmail.com>
|
||||
Leonids Maslovs <leonids.maslovs@galeoconsulting.com>
|
||||
Liam Monahan <liam@monahan.io>
|
||||
Liigo Zhuang <com.liigo@gmail.com>
|
||||
Lindsey Kuper <lindsey@composition.al>
|
||||
Lionel Flandrin <lionel.flandrin@parrot.com>
|
||||
@ -495,6 +543,7 @@ Mathijs van de Nes <git@mathijs.vd-nes.nl>
|
||||
Matt Brubeck <mbrubeck@limpet.net>
|
||||
Matt Carberry <carberry.matt@gmail.com>
|
||||
Matt Coffin <mcoffin13@gmail.com>
|
||||
Matt Cox <mattcoxpdx@gmail.com>
|
||||
Matt McPherrin <git@mcpherrin.ca>
|
||||
Matt Murphy <matthew.john.murphy@gmail.com>
|
||||
Matt Roche <angst7@gmail.com>
|
||||
@ -532,6 +581,7 @@ Michael Sullivan <sully@msully.net>
|
||||
Michael Williams <m.t.williams@live.com>
|
||||
Michael Woerister <michaelwoerister@posteo>
|
||||
Michael Zhou <moz@google.com>
|
||||
Michał Krasnoborski <mkrdln@gmail.com>
|
||||
Mick Koch <kchmck@gmail.com>
|
||||
Mickaël Delahaye <mickael.delahaye@gmail.com>
|
||||
Mihnea Dobrescu-Balaur <mihnea@linux.com>
|
||||
@ -559,7 +609,9 @@ Nathaniel Theis <nttheis@gmail.com>
|
||||
Neil Pankey <npankey@gmail.com>
|
||||
Nelson Chen <crazysim@gmail.com>
|
||||
NiccosSystem <niccossystem@gmail.com>
|
||||
Nicholas <npmazzuca@gmail.com>
|
||||
Nicholas Bishop <nicholasbishop@gmail.com>
|
||||
Nicholas Mazzuca <npmazzuca@gmail.com>
|
||||
Nick Cameron <ncameron@mozilla.com>
|
||||
Nick Desaulniers <ndesaulniers@mozilla.com>
|
||||
Nick Howell <howellnick@gmail.com>
|
||||
@ -579,8 +631,10 @@ Oliver Schneider <oliver.schneider@kit.edu>
|
||||
Olivier Saut <osaut@airpost.net>
|
||||
Olle Jonsson <olle.jonsson@gmail.com>
|
||||
Or Brostovski <tohava@gmail.com>
|
||||
Or Neeman <oneeman@gmail.com>
|
||||
Oren Hazi <oren.hazi@gmail.com>
|
||||
Orpheus Lummis <o@orpheuslummis.com>
|
||||
Orphée Lafond-Lummis <o@orftz.com>
|
||||
P1start <rewi-github@whanau.org>
|
||||
Pablo Brasero <pablo@pablobm.com>
|
||||
Palmer Cox <p@lmercox.com>
|
||||
@ -590,8 +644,11 @@ Patrick Reisert <kpreisert@gmail.com>
|
||||
Patrick Walton <pcwalton@mimiga.net>
|
||||
Patrick Yevsukov <patrickyevsukov@users.noreply.github.com>
|
||||
Patrik Kårlin <patrik.karlin@gmail.com>
|
||||
Paul ADENOT <paul@paul.cx>
|
||||
Paul Collier <paul@paulcollier.ca>
|
||||
Paul Collins <paul@ondioline.org>
|
||||
Paul Crowley <paulcrowley@google.com>
|
||||
Paul Osborne <osbpau@gmail.com>
|
||||
Paul Stansifer <paul.stansifer@gmail.com>
|
||||
Paul Woolcock <pwoolcoc+github@gmail.com>
|
||||
Pavel Panchekha <me@pavpanchekha.com>
|
||||
@ -602,6 +659,7 @@ Peter Atashian <retep998@gmail.com>
|
||||
Peter Elmers <peter.elmers@yahoo.com>
|
||||
Peter Hull <peterhull90@gmail.com>
|
||||
Peter Marheine <peter@taricorp.net>
|
||||
Peter Minten <peter@pminten.nl>
|
||||
Peter Schuller <peter.schuller@infidyne.com>
|
||||
Peter Williams <peter@newton.cx>
|
||||
Peter Zotov <whitequark@whitequark.org>
|
||||
@ -620,14 +678,17 @@ Potpourri <pot_pourri@mail.ru>
|
||||
Pradeep Kumar <gohanpra@gmail.com>
|
||||
Prudhvi Krishna Surapaneni <me@prudhvi.net>
|
||||
Pyfisch <pyfisch@gmail.com>
|
||||
Pyry Kontio <pyry.kontio@drasa.eu>
|
||||
Pythoner6 <pythoner6@gmail.com>
|
||||
Q.P.Liu <qpliu@yahoo.com>
|
||||
Rafael Ávila de Espíndola <respindola@mozilla.com>
|
||||
Rahul Horé <hore.rahul@gmail.com>
|
||||
Ralph Bodenner <rkbodenner+github@gmail.com>
|
||||
Ralph Giles <giles@thaumas.net>
|
||||
Ramkumar Ramachandra <artagnon@gmail.com>
|
||||
Randati <anttivan@gmail.com>
|
||||
Raphael Catolino <raphael.catolino@gmail.com>
|
||||
Raphael Nestler <raphael.nestler@gmail.com>
|
||||
Raphael Speyer <rspeyer@gmail.com>
|
||||
Raul Gutierrez S <rgs@itevenworks.net>
|
||||
Ray Clanan <rclanan@utopianconcept.com>
|
||||
@ -637,6 +698,7 @@ Renato Riccieri Santos Zannon <renato@rrsz.com.br>
|
||||
Renato Zannon <renato@rrsz.com.br>
|
||||
Reuben Morais <reuben.morais@gmail.com>
|
||||
Ricardo M. Correia <rcorreia@wizy.org>
|
||||
Ricardo Martins <ricardo@scarybox.net>
|
||||
Rich Lane <rlane@club.cc.cmu.edu>
|
||||
Richard Diamond <wichard@vitalitystudios.com>
|
||||
Richo Healey <richo@psych0tik.net>
|
||||
@ -663,10 +725,13 @@ Russell <rpjohnst@gmail.com>
|
||||
Ruud van Asseldonk <dev@veniogames.com>
|
||||
Ryan Levick <ryan@6wunderkinder.com>
|
||||
Ryan Mulligan <ryan@ryantm.com>
|
||||
Ryan Prichard <ryan.prichard@gmail.com>
|
||||
Ryan Riginding <marc.riginding@gmail.com>
|
||||
Ryan Scheel <ryan.havvy@gmail.com>
|
||||
Ryman <haqkrs@gmail.com>
|
||||
Rüdiger Sonderfeld <ruediger@c-plusplus.de>
|
||||
S Pradeep Kumar <gohanpra@gmail.com>
|
||||
Sae-bom Kim <sae-bom.kim@samsung.com>
|
||||
Salem Talha <salem.a.talha@gmail.com>
|
||||
Samuel Chase <samebchase@gmail.com>
|
||||
Samuel Neves <sneves@dei.uc.pt>
|
||||
@ -678,6 +743,7 @@ Santiago Rodriguez <sanrodari@gmail.com>
|
||||
Saurabh Anand <saurabhanandiit@gmail.com>
|
||||
Scott Jenkins <scottdjwales@gmail.com>
|
||||
Scott Lawrence <bytbox@gmail.com>
|
||||
Scott Olson <scott@scott-olson.org>
|
||||
Sean Chalmers <sclhiannan@gmail.com>
|
||||
Sean Collins <sean@cllns.com>
|
||||
Sean Gillespie <sean.william.g@gmail.com>
|
||||
@ -730,10 +796,13 @@ Tamir Duberstein <tamird@squareup.com>
|
||||
Taras Shpot <mrshpot@gmail.com>
|
||||
Taylor Hutchison <seanthutchison@gmail.com>
|
||||
Ted Horst <ted.horst@earthlink.net>
|
||||
Tero Hänninen <lgvz@users.noreply.github.com>
|
||||
Thad Guidry <thadguidry@gmail.com>
|
||||
Thiago Carvalho <thiago.carvalho@westwing.de>
|
||||
Thiago Pontes <email@thiago.me>
|
||||
Thomas Backman <serenity@exscape.org>
|
||||
Thomas Daede <daede003@umn.edu>
|
||||
Tiago Nobrega <tigarmo@gmail.com>
|
||||
Till Hoeppner <till@hoeppner.ws>
|
||||
Tim Brooks <brooks@cern.ch>
|
||||
Tim Chevalier <chevalier@alum.wellesley.edu>
|
||||
@ -760,6 +829,7 @@ Toni Cárdenas <toni@tcardenas.me>
|
||||
Tony Young <tony@rfw.name>
|
||||
Torsten Weber <TorstenWeber12@gmail.com>
|
||||
Travis Watkins <amaranth@ubuntu.com>
|
||||
Trent Nadeau <tanadeau@gmail.com>
|
||||
Trent Ogren <tedwardo2@gmail.com>
|
||||
Trinick <slicksilver555@mac.com>
|
||||
Tristan Storch <tstorch@math.uni-bielefeld.de>
|
||||
@ -769,9 +839,9 @@ TyOverby <ty@pre-alpha.com>
|
||||
Tycho Sci <tychosci@gmail.com>
|
||||
Tyler Bindon <martica@martica.org>
|
||||
Tyler Thrailkill <tylerbthrailkill@gmail.com>
|
||||
U-NOV2010\eugals
|
||||
Ulrik Sverdrup <root@localhost>
|
||||
Ulysse Carion <ulysse@ulysse.io>
|
||||
User Jyyou <jyyou@plaslab.cs.nctu.edu.tw>
|
||||
Utkarsh Kukreti <utkarshkukreti@gmail.com>
|
||||
Uwe Dauernheim <uwe@dauernheim.net>
|
||||
Vadim Chugunov <vadimcn@gmail.com>
|
||||
@ -797,6 +867,7 @@ Wade Mealing <wmealing@gmail.com>
|
||||
Wangshan Lu <wisagan@gmail.com>
|
||||
WebeWizard <webewizard@gmail.com>
|
||||
Wendell Smith <wendell.smith@yale.edu>
|
||||
Wesley Wiser <wwiser@gmail.com>
|
||||
Will <will@glozer.net>
|
||||
William Ting <io@williamting.com>
|
||||
Willson Mock <willson.mock@gmail.com>
|
||||
@ -817,12 +888,16 @@ Zack Slayton <zack.slayton@gmail.com>
|
||||
Zbigniew Siciarz <zbigniew@siciarz.net>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zooko Wilcox-O'Hearn <zooko@zooko.com>
|
||||
adridu59 <adri-from-59@hotmail.fr>
|
||||
aochagavia <aochagavia92@gmail.com>
|
||||
areski <areski@gmail.com>
|
||||
arturo <arturo@openframeworks.cc>
|
||||
auREAX <mark@xn--hwg34fba.ws>
|
||||
awlnx <alecweber1994@gmail.com>
|
||||
aydin.kim <aydin.kim@samsung.com>
|
||||
b1nd <clint.ryan3@gmail.com>
|
||||
bachm <Ab@vapor.com>
|
||||
bcoopers <coopersmithbrian@gmail.com>
|
||||
blackbeam <aikorsky@gmail.com>
|
||||
blake2-ppc <ulrik.sverdrup@gmail.com>
|
||||
bluss <bluss>
|
||||
@ -835,6 +910,7 @@ comex <comexk@gmail.com>
|
||||
crhino <piraino.chris@gmail.com>
|
||||
dan@daramos.com <dan@daramos.com>
|
||||
darkf <lw9k123@gmail.com>
|
||||
defuz <defuz.net@gmail.com>
|
||||
dgoon <dgoon@dgoon.net>
|
||||
donkopotamus <general@chocolate-fish.com>
|
||||
eliovir <eliovir@gmail.com>
|
||||
@ -845,6 +921,7 @@ fort <e@mail.com>
|
||||
free-Runner <aali07@students.poly.edu>
|
||||
g3xzh <g3xzh@yahoo.com>
|
||||
gamazeps <gamaz3ps@gmail.com>
|
||||
gareth <gareth@gareth-N56VM.(none)>
|
||||
gentlefolk <cemacken@gmail.com>
|
||||
gifnksm <makoto.nksm@gmail.com>
|
||||
hansjorg <hansjorg@gmail.com>
|
||||
@ -860,6 +937,8 @@ joaoxsouls <joaoxsouls@gmail.com>
|
||||
jrincayc <jrincayc@users.noreply.github.com>
|
||||
juxiliary <juxiliary@gmail.com>
|
||||
jxv <joevargas@hush.com>
|
||||
kgv <mail@kgv.name>
|
||||
kjpgit <kjpgit@users.noreply.github.com>
|
||||
klutzy <klutzytheklutzy@gmail.com>
|
||||
korenchkin <korenchkin2@gmail.com>
|
||||
kud1ing <github@kudling.de>
|
||||
@ -868,6 +947,7 @@ kvark <kvarkus@gmail.com>
|
||||
kwantam <kwantam@gmail.com>
|
||||
lpy <pylaurent1314@gmail.com>
|
||||
lucy <ne.tetewi@gmail.com>
|
||||
lummax <luogpg@googlemail.com>
|
||||
lyuts <dioxinu@gmail.com>
|
||||
m-r-r <raybaudroigm@gmail.com>
|
||||
madmalik <matthias.tellen@googlemail.com>
|
||||
@ -882,20 +962,26 @@ mrec <mike.capp@gmail.com>
|
||||
musitdev <philippe.delrieu@free.fr>
|
||||
nathan dotz <nathan.dotz@gmail.com>
|
||||
nham <hamann.nick@gmail.com>
|
||||
niftynif <nif.ward@gmail.com>
|
||||
noam <noam@clusterfoo.com>
|
||||
novalis <novalis@novalis.org>
|
||||
nsf <no.smile.face@gmail.com>
|
||||
nwin <nwin@users.noreply.github.com>
|
||||
oli-obk <github6541940@oli-obk.de>
|
||||
olivren <o.renaud@gmx.fr>
|
||||
osa1 <omeragacan@gmail.com>
|
||||
posixphreak <posixphreak@gmail.com>
|
||||
qwitwa <qwitwa@gmail.com>
|
||||
ray glover <ray@rayglover.net>
|
||||
reedlepee <reedlepee123@gmail.com>
|
||||
reus <reusee@ymail.com>
|
||||
rjz <rj@rjzaworski.com>
|
||||
sevrak <sevrak@rediffmail.com>
|
||||
sheroze1123 <mss385@cornell.edu>
|
||||
smenardpw <sebastien@knoglr.com>
|
||||
sp3d <sp3d@github>
|
||||
startling <tdixon51793@gmail.com>
|
||||
tav <tav@espians.com>
|
||||
th0114nd <th0114nd@gmail.com>
|
||||
theptrk <patrick.tran06@gmail.com>
|
||||
thiagopnts <thiagopnts@gmail.com>
|
||||
@ -911,3 +997,5 @@ xales <xales@naveria.com>
|
||||
zofrex <zofrex@gmail.com>
|
||||
zslayton <zack.slayton@gmail.com>
|
||||
zzmp <zmp@umich.edu>
|
||||
Łukasz Niemier <lukasz@niemier.pl>
|
||||
克雷 <geekcraik@users.noreply.github.com>
|
||||
|
@ -159,6 +159,13 @@
|
||||
#
|
||||
# Admittedly this is a little convoluted.
|
||||
#
|
||||
# If you find yourself working on the make infrastructure itself, and trying to
|
||||
# find the value of a given variable after expansion, you can use:
|
||||
#
|
||||
# make print-VARIABLE_NAME
|
||||
#
|
||||
# To extract it
|
||||
#
|
||||
# </nitty-gritty>
|
||||
#
|
||||
|
||||
|
98
configure
vendored
98
configure
vendored
@ -192,6 +192,7 @@ valopt_core() {
|
||||
then
|
||||
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
|
||||
local V="CFG_${UOP}"
|
||||
local V_PROVIDED="${V}_PROVIDED"
|
||||
eval $V="$DEFAULT"
|
||||
for arg in $CFG_CONFIGURE_ARGS
|
||||
do
|
||||
@ -199,6 +200,7 @@ valopt_core() {
|
||||
then
|
||||
val=$(echo "$arg" | cut -f2 -d=)
|
||||
eval $V=$val
|
||||
eval $V_PROVIDED=1
|
||||
fi
|
||||
done
|
||||
if [ "$SAVE" = "save" ]
|
||||
@ -247,8 +249,10 @@ opt_core() {
|
||||
if [ $DEFAULT -eq 0 ]
|
||||
then
|
||||
FLAG="enable"
|
||||
DEFAULT_FLAG="disable"
|
||||
else
|
||||
FLAG="disable"
|
||||
DEFAULT_FLAG="enable"
|
||||
DOC="don't $DOC"
|
||||
fi
|
||||
|
||||
@ -261,11 +265,19 @@ opt_core() {
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
|
||||
local V="CFG_${FLAG}_${OP}"
|
||||
local V_PROVIDED="CFG_${FLAG}_${OP}_PROVIDED"
|
||||
eval $V=1
|
||||
eval $V_PROVIDED=1
|
||||
if [ "$SAVE" = "save" ]
|
||||
then
|
||||
putvar $V
|
||||
fi
|
||||
elif [ "$arg" = "--${DEFAULT_FLAG}-${OP}" ]
|
||||
then
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
DEFAULT_FLAG=$(echo $DEFAULT_FLAG | tr 'a-z' 'A-Z')
|
||||
local V_PROVIDED="CFG_${DEFAULT_FLAG}_${OP}_PROVIDED"
|
||||
eval $V_PROVIDED=1
|
||||
fi
|
||||
done
|
||||
else
|
||||
@ -523,31 +535,35 @@ fi
|
||||
BOOL_OPTIONS=""
|
||||
VAL_OPTIONS=""
|
||||
|
||||
opt debug 0 "debug mode"
|
||||
opt valgrind 0 "run tests with valgrind (memcheck by default)"
|
||||
opt helgrind 0 "run tests with helgrind instead of memcheck"
|
||||
opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind"
|
||||
opt docs 1 "build standard library documentation"
|
||||
opt compiler-docs 0 "build compiler documentation"
|
||||
opt optimize 1 "build optimized rust code"
|
||||
opt optimize-cxx 1 "build optimized C++ code"
|
||||
opt optimize-llvm 1 "build optimized LLVM"
|
||||
opt optimize-tests 1 "build tests with optimizations"
|
||||
opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang"
|
||||
opt llvm-assertions 1 "build LLVM with assertions"
|
||||
opt debug 1 "build with extra debug fun"
|
||||
opt llvm-assertions 0 "build LLVM with assertions"
|
||||
opt debug-assertions 0 "build with debugging assertions"
|
||||
opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
|
||||
opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
|
||||
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
|
||||
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
|
||||
opt rpath 0 "build rpaths into rustc itself"
|
||||
opt nightly 0 "build nightly packages"
|
||||
opt verify-install 1 "verify installed binaries work"
|
||||
# This is used by the automation to produce single-target nightlies
|
||||
opt dist-host-only 0 "only install bins for the host architecture"
|
||||
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
|
||||
opt jemalloc 1 "build liballoc with jemalloc"
|
||||
opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway"
|
||||
|
||||
# Optimization and debugging options. These may be overridden by the release channel, etc.
|
||||
opt_nosave optimize 1 "build optimized rust code"
|
||||
opt_nosave optimize-cxx 1 "build optimized C++ code"
|
||||
opt_nosave optimize-llvm 1 "build optimized LLVM"
|
||||
opt_nosave llvm-assertions 0 "build LLVM with assertions"
|
||||
opt_nosave debug-assertions 0 "build with debugging assertions"
|
||||
opt_nosave debuginfo 0 "build with debugger metadata"
|
||||
opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
|
||||
|
||||
valopt localstatedir "/var/lib" "local state directory"
|
||||
valopt sysconfdir "/etc" "install system configuration files"
|
||||
|
||||
@ -557,18 +573,19 @@ valopt llvm-root "" "set LLVM root"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
|
||||
valopt release-channel "dev" "the name of the release channel to build"
|
||||
|
||||
# Many of these are saved below during the "writing configuration" step
|
||||
# (others are conditionally saved).
|
||||
opt_nosave manage-submodules 1 "let the build manage the git submodules"
|
||||
opt_nosave clang 0 "prefer clang to gcc for building the runtime"
|
||||
opt_nosave jemalloc 1 "build liballoc with jemalloc"
|
||||
|
||||
valopt_nosave prefix "/usr/local" "set installation prefix"
|
||||
valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
|
||||
valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
|
||||
valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
|
||||
valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
|
||||
valopt_nosave release-channel "dev" "the name of the release channel to build"
|
||||
|
||||
# Temporarily support old triples until buildbots get updated
|
||||
CFG_BUILD=$(to_llvm_triple $CFG_BUILD)
|
||||
@ -612,22 +629,40 @@ fi
|
||||
step_msg "validating $CFG_SELF args"
|
||||
validate_opt
|
||||
|
||||
# Validate the release channel
|
||||
# Validate the release channel, and configure options
|
||||
case "$CFG_RELEASE_CHANNEL" in
|
||||
(dev | nightly | beta | stable)
|
||||
nightly )
|
||||
msg "overriding settings for $CFG_RELEASE_CHANNEL"
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
;;
|
||||
(*)
|
||||
dev | beta | stable)
|
||||
;;
|
||||
*)
|
||||
err "release channel must be 'dev', 'nightly', 'beta' or 'stable'"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Continue supporting the old --enable-nightly flag to transition the bots
|
||||
# XXX Remove me
|
||||
if [ ! -z "$CFG_ENABLE_NIGHTLY" ]
|
||||
then
|
||||
CFG_RELEASE_CHANNEL=nightly
|
||||
# Adjust perf and debug options for debug mode
|
||||
if [ -n "$CFG_ENABLE_DEBUG" ]; then
|
||||
msg "debug mode enabled, setting performance options"
|
||||
if [ -z "$CFG_ENABLE_OPTIMIZE_PROVIDED" ]; then
|
||||
msg "optimization not explicitly enabled, disabling optimization"
|
||||
CFG_DISABLE_OPTIMIZE=1
|
||||
CFG_DISABLE_OPTIMIZE_CXX=1
|
||||
fi
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
CFG_ENABLE_DEBUG_ASSERTIONS=1
|
||||
CFG_ENABLE_DEBUG_JEMALLOC=1
|
||||
fi
|
||||
putvar CFG_RELEASE_CHANNEL
|
||||
|
||||
# OK, now write the debugging options
|
||||
if [ -n "$CFG_DISABLE_OPTIMIZE" ]; then putvar CFG_DISABLE_OPTIMIZE; fi
|
||||
if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi
|
||||
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi
|
||||
if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
|
||||
|
||||
# A magic value that allows the compiler to use unstable features
|
||||
# during the bootstrap even when doing so would normally be an error
|
||||
@ -669,7 +704,6 @@ probe CFG_LD ld
|
||||
probe CFG_VALGRIND valgrind
|
||||
probe CFG_PERF perf
|
||||
probe CFG_ISCC iscc
|
||||
probe CFG_JAVAC javac
|
||||
probe CFG_ANTLR4 antlr4
|
||||
probe CFG_GRUN grun
|
||||
probe CFG_FLEX flex
|
||||
@ -679,6 +713,14 @@ probe CFG_XELATEX xelatex
|
||||
probe CFG_GDB gdb
|
||||
probe CFG_LLDB lldb
|
||||
|
||||
# On MacOS X, invoking `javac` pops up a dialog if the JDK is not
|
||||
# installed. Since `javac` is only used if `antlr4` is available,
|
||||
# probe for it only in this case.
|
||||
if [ ! -z "$CFG_ANTLR4" ]
|
||||
then
|
||||
probe CFG_JAVAC javac
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_GDB" ]
|
||||
then
|
||||
# Store GDB's version
|
||||
@ -775,7 +817,7 @@ if [ $CFG_OSTYPE = unknown-bitrig ]
|
||||
then
|
||||
step_msg "on Bitrig, forcing use of clang, disabling jemalloc"
|
||||
CFG_ENABLE_CLANG=1
|
||||
CFG_ENABLE_JEMALLOC=0
|
||||
CFG_DISABLE_JEMALLOC=1
|
||||
fi
|
||||
|
||||
if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
|
||||
@ -828,6 +870,12 @@ then
|
||||
putvar CFG_ENABLE_CLANG
|
||||
fi
|
||||
|
||||
# Same with jemalloc. save the setting here.
|
||||
if [ ! -z "$CFG_DISABLE_JEMALLOC" ]
|
||||
then
|
||||
putvar CFG_DISABLE_JEMALLOC
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_LLVM_ROOT" -a -z "$CFG_DISABLE_LLVM_VERSION_CHECK" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ]
|
||||
then
|
||||
step_msg "using custom LLVM at $CFG_LLVM_ROOT"
|
||||
@ -1095,6 +1143,7 @@ do
|
||||
make_dir $h/test/debuginfo-gdb
|
||||
make_dir $h/test/debuginfo-lldb
|
||||
make_dir $h/test/codegen
|
||||
make_dir $h/test/rustdoc
|
||||
done
|
||||
|
||||
# Configure submodules
|
||||
@ -1167,7 +1216,7 @@ do
|
||||
LLVM_DBG_OPTS="--enable-optimized"
|
||||
LLVM_INST_DIR=$LLVM_BUILD_DIR/Release
|
||||
fi
|
||||
if [ ! -z "$CFG_DISABLE_LLVM_ASSERTIONS" ]
|
||||
if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ]
|
||||
then
|
||||
LLVM_ASSERTION_OPTS="--disable-assertions"
|
||||
else
|
||||
@ -1421,6 +1470,11 @@ move_if_changed config.tmp config.mk
|
||||
rm -f config.tmp
|
||||
touch config.stamp
|
||||
|
||||
step_msg "complete"
|
||||
if [ -z "$CFG_ENABLE_DEBUG" ]; then
|
||||
step_msg "configured in release mode. for development consider --enable-debug"
|
||||
else
|
||||
step_msg "complete"
|
||||
fi
|
||||
|
||||
msg "run \`make help\`"
|
||||
msg
|
||||
|
35
mk/crates.mk
35
mk/crates.mk
@ -118,42 +118,13 @@ ONLY_RLIB_collections := 1
|
||||
ONLY_RLIB_unicode := 1
|
||||
ONLY_RLIB_rustc_bitflags := 1
|
||||
|
||||
# Documented-by-default crates
|
||||
DOC_CRATES := std alloc collections core libc unicode
|
||||
|
||||
################################################################################
|
||||
# You should not need to edit below this line
|
||||
################################################################################
|
||||
|
||||
# On channels where the only usable crate is std, only build documentation for
|
||||
# std. This keeps distributions small and doesn't clutter up the API docs with
|
||||
# confusing internal details from the crates behind the facade.
|
||||
#
|
||||
# (Disabled while cmr figures out how to change rustdoc to make reexports work
|
||||
# slightly nicer. Otherwise, all cross-crate links to Vec will go to
|
||||
# libcollections, breaking them, and [src] links for anything reexported will
|
||||
# not work.)
|
||||
|
||||
#ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
#DOC_CRATES := std
|
||||
#else
|
||||
#ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
||||
#DOC_CRATES := std
|
||||
#else
|
||||
DOC_CRATES := $(filter-out rustc, \
|
||||
$(filter-out rustc_trans, \
|
||||
$(filter-out rustc_typeck, \
|
||||
$(filter-out rustc_borrowck, \
|
||||
$(filter-out rustc_resolve, \
|
||||
$(filter-out rustc_driver, \
|
||||
$(filter-out rustc_privacy, \
|
||||
$(filter-out rustc_lint, \
|
||||
$(filter-out log, \
|
||||
$(filter-out getopts, \
|
||||
$(filter-out syntax, $(CRATES))))))))))))
|
||||
#endif
|
||||
#endif
|
||||
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
|
||||
rustc_typeck rustc_driver syntax rustc_privacy \
|
||||
rustc_lint
|
||||
|
||||
# This macro creates some simple definitions for each crate being built, just
|
||||
# some munging of all of the parameters above.
|
||||
#
|
||||
|
10
mk/docs.mk
10
mk/docs.mk
@ -250,18 +250,20 @@ endif
|
||||
doc/$(1)/:
|
||||
$$(Q)mkdir -p $$@
|
||||
|
||||
$(2) += doc/$(1)/index.html
|
||||
doc/$(1)/index.html: CFG_COMPILER_HOST_TRIPLE = $(CFG_TARGET)
|
||||
doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
|
||||
@$$(call E, rustdoc: $$@)
|
||||
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(CFG_BUILD)) \
|
||||
$$(RUSTDOC) --cfg dox --cfg stage2 $$<
|
||||
$$(RUSTDOC) --cfg dox --cfg stage2 $$(RUSTFLAGS_$(1)) $$<
|
||||
endef
|
||||
|
||||
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
|
||||
$(foreach crate,$(CRATES),$(eval $(call DEF_LIB_DOC,$(crate))))
|
||||
|
||||
COMPILER_DOC_TARGETS := $(CRATES:%=doc/%/index.html)
|
||||
ifdef CFG_COMPILER_DOCS
|
||||
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS)))
|
||||
DOC_TARGETS += $(COMPILER_DOC_TARGETS)
|
||||
else
|
||||
DOC_TARGETS += $(DOC_CRATES:%=doc/%/index.html)
|
||||
endif
|
||||
|
||||
ifdef CFG_DISABLE_DOCS
|
||||
|
@ -8,12 +8,6 @@
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
ifdef CFG_DISABLE_VERIFY_INSTALL
|
||||
MAYBE_DISABLE_VERIFY=--disable-verify
|
||||
else
|
||||
MAYBE_DISABLE_VERIFY=
|
||||
endif
|
||||
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
# Build the dist as the original user
|
||||
@ -22,9 +16,9 @@ else
|
||||
$(Q)$(MAKE) prepare_install
|
||||
endif
|
||||
ifeq ($(CFG_DISABLE_DOCS),)
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
endif
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
|
||||
$(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
# Remove tmp files because it's a decent amount of disk space
|
||||
$(Q)rm -R tmp/dist
|
||||
|
||||
|
15
mk/main.mk
15
mk/main.mk
@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.0
|
||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||
# versions (section 9)
|
||||
CFG_PRERELEASE_VERSION=
|
||||
CFG_PRERELEASE_VERSION=.3
|
||||
|
||||
CFG_FILENAME_EXTRA=4e7c5e5c
|
||||
|
||||
@ -126,11 +126,16 @@ endif
|
||||
|
||||
CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS)
|
||||
|
||||
ifdef CFG_DISABLE_DEBUG
|
||||
CFG_RUSTC_FLAGS += --cfg ndebug
|
||||
else
|
||||
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
|
||||
ifdef CFG_ENABLE_DEBUG_ASSERTIONS
|
||||
$(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS))
|
||||
CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
|
||||
else
|
||||
CFG_RUSTC_FLAGS += --cfg ndebug
|
||||
endif
|
||||
|
||||
ifdef CFG_ENABLE_DEBUGINFO
|
||||
$(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO))
|
||||
CFG_RUSTC_FLAGS += -g
|
||||
endif
|
||||
|
||||
ifdef SAVE_TEMPS
|
||||
|
4
mk/rt.mk
4
mk/rt.mk
@ -143,6 +143,10 @@ else ifeq ($(findstring android, $(OSTYPE_$(1))), android)
|
||||
JEMALLOC_ARGS_$(1) := --disable-tls
|
||||
endif
|
||||
|
||||
ifdef CFG_ENABLE_DEBUG_JEMALLOC
|
||||
JEMALLOC_ARGS_$(1) += --enable-debug --enable-fill
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# jemalloc
|
||||
################################################################################
|
||||
|
23
mk/tests.mk
23
mk/tests.mk
@ -22,9 +22,11 @@ $(eval $(call RUST_CRATE,coretest))
|
||||
DEPS_collectionstest :=
|
||||
$(eval $(call RUST_CRATE,collectionstest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) collectionstest coretest
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES)
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
rustc_trans rustc_lint,\
|
||||
$(HOST_CRATES))
|
||||
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
|
||||
|
||||
@ -304,6 +306,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-bench-exec \
|
||||
@ -471,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
|
||||
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
|
||||
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
|
||||
|
||||
# perf tests are the same as bench tests only they run under
|
||||
# a performance monitor.
|
||||
@ -489,6 +493,7 @@ PRETTY_TESTS := $(PRETTY_RS)
|
||||
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
|
||||
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
|
||||
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
|
||||
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
|
||||
|
||||
CTEST_SRC_BASE_rpass = run-pass
|
||||
CTEST_BUILD_BASE_rpass = run-pass
|
||||
@ -550,6 +555,11 @@ CTEST_BUILD_BASE_codegen = codegen
|
||||
CTEST_MODE_codegen = codegen
|
||||
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_rustdocck = rustdoc
|
||||
CTEST_BUILD_BASE_rustdocck = rustdoc
|
||||
CTEST_MODE_rustdocck = rustdoc
|
||||
CTEST_RUNTOOL_rustdocck = $(CTEST_RUNTOOL)
|
||||
|
||||
# CTEST_DISABLE_$(TEST_GROUP), if set, will cause the test group to be
|
||||
# disabled and the associated message to be printed as a warning
|
||||
# during attempts to run those tests.
|
||||
@ -618,12 +628,14 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
--compile-lib-path $$(HLIB$(1)_H_$(3)) \
|
||||
--run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \
|
||||
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||
--rustdoc-path $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
--clang-path $(if $(CFG_CLANG),$(CFG_CLANG),clang) \
|
||||
--llvm-bin-path $(CFG_LLVM_INST_DIR_$(CFG_BUILD))/bin \
|
||||
--aux-base $$(S)src/test/auxiliary/ \
|
||||
--stage-id stage$(1)-$(2) \
|
||||
--target $(2) \
|
||||
--host $(3) \
|
||||
--python $$(CFG_PYTHON) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--lldb-version="$(CFG_LLDB_VERSION)" \
|
||||
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
|
||||
@ -660,6 +672,9 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
|
||||
$(S)src/etc/lldb_batchmode.py \
|
||||
$(S)src/etc/lldb_rust_formatters.py
|
||||
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
|
||||
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
|
||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
$(S)src/etc/htmldocck.py
|
||||
|
||||
endef
|
||||
|
||||
@ -722,7 +737,8 @@ endif
|
||||
|
||||
endef
|
||||
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail bench perf debuginfo-gdb debuginfo-lldb codegen
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
|
||||
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval $(foreach target,$(CFG_TARGET), \
|
||||
@ -890,6 +906,7 @@ TEST_GROUPS = \
|
||||
bench \
|
||||
perf \
|
||||
rmake \
|
||||
rustdocck \
|
||||
debuginfo-gdb \
|
||||
debuginfo-lldb \
|
||||
codegen \
|
||||
|
@ -16,4 +16,7 @@ else
|
||||
E = echo $(1)
|
||||
endif
|
||||
|
||||
print-%:
|
||||
@echo $*=$($*)
|
||||
|
||||
S := $(CFG_SRC_DIR)
|
||||
|
@ -23,7 +23,8 @@ pub enum Mode {
|
||||
Pretty,
|
||||
DebugInfoGdb,
|
||||
DebugInfoLldb,
|
||||
Codegen
|
||||
Codegen,
|
||||
Rustdoc,
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
@ -39,6 +40,7 @@ impl FromStr for Mode {
|
||||
"debuginfo-lldb" => Ok(DebugInfoLldb),
|
||||
"debuginfo-gdb" => Ok(DebugInfoGdb),
|
||||
"codegen" => Ok(Codegen),
|
||||
"rustdoc" => Ok(Rustdoc),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@ -56,6 +58,7 @@ impl fmt::Display for Mode {
|
||||
DebugInfoGdb => "debuginfo-gdb",
|
||||
DebugInfoLldb => "debuginfo-lldb",
|
||||
Codegen => "codegen",
|
||||
Rustdoc => "rustdoc",
|
||||
}, f)
|
||||
}
|
||||
}
|
||||
@ -71,6 +74,12 @@ pub struct Config {
|
||||
// The rustc executable
|
||||
pub rustc_path: PathBuf,
|
||||
|
||||
// The rustdoc executable
|
||||
pub rustdoc_path: PathBuf,
|
||||
|
||||
// The python executable
|
||||
pub python: String,
|
||||
|
||||
// The clang executable
|
||||
pub clang_path: Option<PathBuf>,
|
||||
|
||||
|
@ -12,16 +12,16 @@
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
#![feature(old_io)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(std_misc)]
|
||||
#![feature(test)]
|
||||
#![feature(path_ext)]
|
||||
#![feature(str_char)]
|
||||
#![feature(libc)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate libc;
|
||||
extern crate test;
|
||||
extern crate getopts;
|
||||
|
||||
@ -42,6 +42,7 @@ pub mod header;
|
||||
pub mod runtest;
|
||||
pub mod common;
|
||||
pub mod errors;
|
||||
mod raise_fd_limit;
|
||||
|
||||
pub fn main() {
|
||||
let config = parse_config(env::args().collect());
|
||||
@ -60,6 +61,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
|
||||
reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
|
||||
reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
|
||||
reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"),
|
||||
reqopt("", "python", "path to python to use for doc tests", "PATH"),
|
||||
optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
|
||||
optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"),
|
||||
optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"),
|
||||
@ -128,6 +131,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
|
||||
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
|
||||
rustc_path: opt_path(matches, "rustc-path"),
|
||||
rustdoc_path: opt_path(matches, "rustdoc-path"),
|
||||
python: matches.opt_str("python").unwrap(),
|
||||
clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
|
||||
valgrind_path: matches.opt_str("valgrind-path"),
|
||||
force_valgrind: matches.opt_present("force-valgrind"),
|
||||
@ -168,6 +173,7 @@ pub fn log_config(config: &Config) {
|
||||
logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
|
||||
logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
|
||||
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
|
||||
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path.display()));
|
||||
logv(c, format!("src_base: {:?}", config.src_base.display()));
|
||||
logv(c, format!("build_base: {:?}", config.build_base.display()));
|
||||
logv(c, format!("stage_id: {}", config.stage_id));
|
||||
@ -240,11 +246,7 @@ pub fn run_tests(config: &Config) {
|
||||
// sadly osx needs some file descriptor limits raised for running tests in
|
||||
// parallel (especially when we have lots and lots of child processes).
|
||||
// For context, see #8904
|
||||
#[allow(deprecated)]
|
||||
fn raise_fd_limit() {
|
||||
std::old_io::test::raise_fd_limit();
|
||||
}
|
||||
raise_fd_limit();
|
||||
unsafe { raise_fd_limit::raise_fd_limit(); }
|
||||
// Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
|
||||
// If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
|
||||
env::set_var("__COMPAT_LAYER", "RunAsInvoker");
|
||||
@ -366,7 +368,7 @@ pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::Test
|
||||
fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
match full_version_line {
|
||||
Some(ref full_version_line)
|
||||
if full_version_line.trim().len() > 0 => {
|
||||
if !full_version_line.trim().is_empty() => {
|
||||
let full_version_line = full_version_line.trim();
|
||||
|
||||
// used to be a regex "(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)"
|
||||
@ -406,7 +408,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
|
||||
match full_version_line {
|
||||
Some(ref full_version_line)
|
||||
if full_version_line.trim().len() > 0 => {
|
||||
if !full_version_line.trim().is_empty() => {
|
||||
let full_version_line = full_version_line.trim();
|
||||
|
||||
for (pos, l) in full_version_line.char_indices() {
|
||||
@ -424,7 +426,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
let vers = full_version_line[pos + 5..].chars().take_while(|c| {
|
||||
c.is_digit(10)
|
||||
}).collect::<String>();
|
||||
if vers.len() > 0 { return Some(vers) }
|
||||
if !vers.is_empty() { return Some(vers) }
|
||||
}
|
||||
println!("Could not extract LLDB version from line '{}'",
|
||||
full_version_line);
|
||||
|
79
src/compiletest/raise_fd_limit.rs
Normal file
79
src/compiletest/raise_fd_limit.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X
|
||||
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
|
||||
/// ends up being far too low for our multithreaded scheduler testing, depending
|
||||
/// on the number of cores available.
|
||||
///
|
||||
/// This fixes issue #7772.
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub unsafe fn raise_fd_limit() {
|
||||
use libc;
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
use std::mem::size_of_val;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
type rlim_t = libc::uint64_t;
|
||||
|
||||
#[repr(C)]
|
||||
struct rlimit {
|
||||
rlim_cur: rlim_t,
|
||||
rlim_max: rlim_t
|
||||
}
|
||||
extern {
|
||||
// name probably doesn't need to be mut, but the C function doesn't
|
||||
// specify const
|
||||
fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
|
||||
oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
|
||||
newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
|
||||
fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
|
||||
fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int;
|
||||
}
|
||||
static CTL_KERN: libc::c_int = 1;
|
||||
static KERN_MAXFILESPERPROC: libc::c_int = 29;
|
||||
static RLIMIT_NOFILE: libc::c_int = 8;
|
||||
|
||||
// The strategy here is to fetch the current resource limits, read the
|
||||
// kern.maxfilesperproc sysctl value, and bump the soft resource limit for
|
||||
// maxfiles up to the sysctl value.
|
||||
|
||||
// Fetch the kern.maxfilesperproc value
|
||||
let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
|
||||
let mut maxfiles: libc::c_int = 0;
|
||||
let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
|
||||
if sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size,
|
||||
null_mut(), 0) != 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
panic!("raise_fd_limit: error calling sysctl: {}", err);
|
||||
}
|
||||
|
||||
// Fetch the current resource limits
|
||||
let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
|
||||
if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
panic!("raise_fd_limit: error calling getrlimit: {}", err);
|
||||
}
|
||||
|
||||
// Bump the soft limit to the smaller of kern.maxfilesperproc and the hard
|
||||
// limit
|
||||
rlim.rlim_cur = cmp::min(maxfiles as rlim_t, rlim.rlim_max);
|
||||
|
||||
// Set our newly-increased resource limit
|
||||
if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
panic!("raise_fd_limit: error calling setrlimit: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
pub unsafe fn raise_fd_limit() {}
|
@ -12,7 +12,7 @@ use self::TargetLocation::*;
|
||||
|
||||
use common::Config;
|
||||
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
|
||||
use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
|
||||
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc};
|
||||
use errors;
|
||||
use header::TestProps;
|
||||
use header;
|
||||
@ -29,7 +29,6 @@ use std::net::TcpStream;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output, ExitStatus};
|
||||
use std::str;
|
||||
use std::time::Duration;
|
||||
use test::MetricMap;
|
||||
|
||||
pub fn run(config: Config, testfile: &Path) {
|
||||
@ -57,15 +56,16 @@ pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
|
||||
let props = header::load_props(&testfile);
|
||||
debug!("loaded props");
|
||||
match config.mode {
|
||||
CompileFail => run_cfail_test(&config, &props, &testfile),
|
||||
ParseFail => run_cfail_test(&config, &props, &testfile),
|
||||
RunFail => run_rfail_test(&config, &props, &testfile),
|
||||
RunPass => run_rpass_test(&config, &props, &testfile),
|
||||
RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
|
||||
Pretty => run_pretty_test(&config, &props, &testfile),
|
||||
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
|
||||
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
|
||||
Codegen => run_codegen_test(&config, &props, &testfile, mm),
|
||||
CompileFail => run_cfail_test(&config, &props, &testfile),
|
||||
ParseFail => run_cfail_test(&config, &props, &testfile),
|
||||
RunFail => run_rfail_test(&config, &props, &testfile),
|
||||
RunPass => run_rpass_test(&config, &props, &testfile),
|
||||
RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
|
||||
Pretty => run_pretty_test(&config, &props, &testfile),
|
||||
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
|
||||
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
|
||||
Codegen => run_codegen_test(&config, &props, &testfile, mm),
|
||||
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,7 +382,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
|
||||
// write debugger script
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
script_str.push_str("set charset UTF-8\n");
|
||||
script_str.push_str(&format!("set charset {}\n", charset()));
|
||||
script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
|
||||
script_str.push_str("target remote :5039\n");
|
||||
script_str.push_str(&format!("set solib-search-path \
|
||||
@ -451,11 +451,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
.expect(&format!("failed to exec `{:?}`", config.adb_path));
|
||||
loop {
|
||||
//waiting 1 second for gdbserver start
|
||||
#[allow(deprecated)]
|
||||
fn sleep() {
|
||||
::std::old_io::timer::sleep(Duration::milliseconds(1000));
|
||||
}
|
||||
sleep();
|
||||
::std::thread::sleep_ms(1000);
|
||||
if TcpStream::connect("127.0.0.1:5039").is_ok() {
|
||||
break
|
||||
}
|
||||
@ -516,8 +512,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
.to_string();
|
||||
// write debugger script
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
|
||||
script_str.push_str("set charset UTF-8\n");
|
||||
script_str.push_str(&format!("set charset {}\n", charset()));
|
||||
script_str.push_str("show version\n");
|
||||
|
||||
match config.gdb_version {
|
||||
@ -726,32 +721,37 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
|
||||
-> ProcRes {
|
||||
// Prepare the lldb_batchmode which executes the debugger script
|
||||
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
|
||||
cmd2procres(config,
|
||||
test_executable,
|
||||
Command::new(&config.python)
|
||||
.arg(&lldb_script_path)
|
||||
.arg(test_executable)
|
||||
.arg(debugger_script)
|
||||
.env("PYTHONPATH",
|
||||
config.lldb_python_dir.as_ref().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
let mut cmd = Command::new("python");
|
||||
cmd.arg(&lldb_script_path)
|
||||
.arg(test_executable)
|
||||
.arg(debugger_script)
|
||||
.env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
|
||||
fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command)
|
||||
-> ProcRes {
|
||||
let (status, out, err) = match cmd.output() {
|
||||
Ok(Output { status, stdout, stderr }) => {
|
||||
(status,
|
||||
String::from_utf8(stdout).unwrap(),
|
||||
String::from_utf8(stderr).unwrap())
|
||||
},
|
||||
Err(e) => {
|
||||
fatal(&format!("Failed to setup Python process for \
|
||||
LLDB script: {}", e))
|
||||
}
|
||||
};
|
||||
|
||||
let (status, out, err) = match cmd.output() {
|
||||
Ok(Output { status, stdout, stderr }) => {
|
||||
(status,
|
||||
String::from_utf8(stdout).unwrap(),
|
||||
String::from_utf8(stderr).unwrap())
|
||||
},
|
||||
Err(e) => {
|
||||
fatal(&format!("Failed to setup Python process for \
|
||||
LLDB script: {}", e))
|
||||
}
|
||||
};
|
||||
|
||||
dump_output(config, test_executable, &out, &err);
|
||||
return ProcRes {
|
||||
status: Status::Normal(status),
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline: format!("{:?}", cmd)
|
||||
};
|
||||
dump_output(config, test_executable, &out, &err);
|
||||
ProcRes {
|
||||
status: Status::Normal(status),
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline: format!("{:?}", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@ -864,7 +864,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if !failed && rest.len() == 0 {
|
||||
if !failed && rest.is_empty() {
|
||||
i += 1;
|
||||
}
|
||||
if i == num_check_lines {
|
||||
@ -1158,6 +1158,26 @@ fn compile_test_(config: &Config, props: &TestProps,
|
||||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
||||
fn document(config: &Config, props: &TestProps,
|
||||
testfile: &Path, extra_args: &[String]) -> (ProcRes, PathBuf) {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
let out_dir = output_base_name(config, testfile);
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
ensure_dir(&out_dir);
|
||||
let mut args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string(),
|
||||
"-o".to_string(),
|
||||
out_dir.to_str().unwrap().to_string(),
|
||||
testfile.to_str().unwrap().to_string()];
|
||||
args.extend(extra_args.iter().cloned());
|
||||
args.extend(split_maybe_args(&props.compile_flags).into_iter());
|
||||
let args = ProcArgs {
|
||||
prog: config.rustdoc_path.to_str().unwrap().to_string(),
|
||||
args: args,
|
||||
};
|
||||
(compose_and_run_compiler(config, props, testfile, args, None), out_dir)
|
||||
}
|
||||
|
||||
fn exec_compiled_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
|
||||
@ -1182,20 +1202,17 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
|
||||
}
|
||||
}
|
||||
|
||||
fn compose_and_run_compiler(
|
||||
config: &Config,
|
||||
props: &TestProps,
|
||||
testfile: &Path,
|
||||
args: ProcArgs,
|
||||
input: Option<String>) -> ProcRes {
|
||||
|
||||
fn compose_and_run_compiler(config: &Config, props: &TestProps,
|
||||
testfile: &Path, args: ProcArgs,
|
||||
input: Option<String>) -> ProcRes {
|
||||
if !props.aux_builds.is_empty() {
|
||||
ensure_dir(&aux_output_dir_name(config, testfile));
|
||||
}
|
||||
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
|
||||
let extra_link_args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string()];
|
||||
|
||||
for rel_ab in &props.aux_builds {
|
||||
let abs_ab = config.aux_base.join(rel_ab);
|
||||
@ -1331,8 +1348,8 @@ fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
|
||||
f
|
||||
}
|
||||
|
||||
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
|
||||
ProcArgs {
|
||||
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path)
|
||||
-> ProcArgs {
|
||||
// If we've got another tool to run under (valgrind),
|
||||
// then split apart its command
|
||||
let mut args = split_maybe_args(&config.runtool);
|
||||
@ -1645,7 +1662,7 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
|
||||
// codegen tests (vs. clang)
|
||||
|
||||
fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf {
|
||||
if suffix.len() == 0 {
|
||||
if suffix.is_empty() {
|
||||
p.to_path_buf()
|
||||
} else {
|
||||
let mut stem = p.file_stem().unwrap().to_os_string();
|
||||
@ -1790,3 +1807,29 @@ fn run_codegen_test(config: &Config, props: &TestProps,
|
||||
(base_lines as f64) / (clang_lines as f64),
|
||||
0.001);
|
||||
}
|
||||
|
||||
fn charset() -> &'static str {
|
||||
if cfg!(any(target_os = "bitrig", target_os = "freebsd")) {
|
||||
"auto"
|
||||
} else {
|
||||
"UTF-8"
|
||||
}
|
||||
}
|
||||
|
||||
fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let (proc_res, out_dir) = document(config, props, testfile, &[]);
|
||||
if !proc_res.status.success() {
|
||||
fatal_proc_rec("rustdoc failed!", &proc_res);
|
||||
}
|
||||
let root = find_rust_src_root(config).unwrap();
|
||||
|
||||
let res = cmd2procres(config,
|
||||
testfile,
|
||||
Command::new(&config.python)
|
||||
.arg(root.join("src/etc/htmldocck.py"))
|
||||
.arg(out_dir)
|
||||
.arg(testfile));
|
||||
if !res.status.success() {
|
||||
fatal_proc_rec("htmldocck failed!", &res);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ Types which are [`Sync`][sync] are thread-safe when multiple shared
|
||||
references to them are used concurrently. Types which are not `Sync` are not
|
||||
thread-safe, and thus when used in a global require unsafe code to use.
|
||||
|
||||
[sync]: core/kinds/trait.Sync.html
|
||||
[sync]: core/marker/trait.Sync.html
|
||||
|
||||
### If mutable static items that implement `Sync` are safe, why is taking &mut SHARABLE unsafe?
|
||||
|
||||
@ -139,7 +139,7 @@ and explicitly calling the `clone` method. Making user-defined copy operators
|
||||
explicit surfaces the underlying complexity, forcing the developer to opt-in
|
||||
to potentially expensive operations.
|
||||
|
||||
[copy]: core/kinds/trait.Copy.html
|
||||
[copy]: core/marker/trait.Copy.html
|
||||
[clone]: core/clone/trait.Clone.html
|
||||
|
||||
## No move constructors
|
||||
@ -163,13 +163,18 @@ This is to make the language easier to parse for humans, especially in the face
|
||||
of higher-order functions. `fn foo<T>(f: fn(int): int, fn(T): U): U` is not
|
||||
particularly easy to read.
|
||||
|
||||
## `let` is used to introduce variables
|
||||
## Why is `let` used to introduce variables?
|
||||
|
||||
`let` not only defines variables, but can do pattern matching. One can also
|
||||
redeclare immutable variables with `let`. This is useful to avoid unnecessary
|
||||
`mut` annotations. An interesting historical note is that Rust comes,
|
||||
syntactically, most closely from ML, which also uses `let` to introduce
|
||||
bindings.
|
||||
Instead of the term "variable", we use "variable bindings". The
|
||||
simplest way for creating a binding is by using the `let` syntax.
|
||||
Other ways include `if let`, `while let`, and `match`. Bindings also
|
||||
exist in function argument positions.
|
||||
|
||||
Bindings always happen in pattern matching positions, and it's also Rust's way
|
||||
to declare mutability. One can also re-declare mutability of a binding in
|
||||
pattern matching. This is useful to avoid unnecessary `mut` annotations. An
|
||||
interesting historical note is that Rust comes, syntactically, most closely
|
||||
from ML, which also uses `let` to introduce bindings.
|
||||
|
||||
See also [a long thread][alt] on renaming `let mut` to `var`.
|
||||
|
||||
|
@ -42,10 +42,7 @@ Let the fact that this is an easily countable number be a warning.
|
||||
|
||||
## Does it run on Windows?
|
||||
|
||||
Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). Note that the Windows implementation currently has some limitations; in particular, the 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc].
|
||||
|
||||
[win64]: https://github.com/rust-lang/rust/issues/1237
|
||||
[libgcc]: https://github.com/rust-lang/rust/issues/11782
|
||||
Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin).
|
||||
|
||||
## Is it OO? How do I do this thing I normally do in an OO language?
|
||||
|
||||
|
@ -15,6 +15,12 @@ Rust, its syntax, and its concepts. Upon completing the book, you'll be an
|
||||
intermediate Rust developer, and will have a good grasp of the fundamental
|
||||
ideas behind Rust.
|
||||
|
||||
[Rust By Example][rbe] was originally a community resource, but was then
|
||||
donated to the Rust project. As the name implies, it teaches you Rust through a
|
||||
series of small examples.
|
||||
|
||||
[rbe]: http://rustbyexample.com/
|
||||
|
||||
# Community & Getting Help
|
||||
|
||||
If you need help with something, or just want to talk about Rust with others,
|
||||
@ -76,17 +82,3 @@ We have [API documentation for the entire standard
|
||||
library](std/index.html). There's a list of crates on the left with more
|
||||
specific sections, or you can use the search bar at the top to search for
|
||||
something if you know its name.
|
||||
|
||||
# External documentation
|
||||
|
||||
*Note: While these are great resources for learning Rust, they may track a
|
||||
particular version of Rust that is likely not exactly the same as that for
|
||||
which this documentation was generated.*
|
||||
|
||||
* [Rust by Example] - Short examples of common tasks in Rust (tracks the master
|
||||
branch).
|
||||
* [Rust for Rubyists] - The first community tutorial for Rust. Tracks the last
|
||||
stable release. Not just for Ruby programmers.
|
||||
|
||||
[Rust by Example]: http://rustbyexample.com/
|
||||
[Rust for Rubyists]: http://www.rustforrubyists.com/
|
||||
|
589
src/doc/intro.md
589
src/doc/intro.md
@ -1,590 +1,5 @@
|
||||
% A 30-minute Introduction to Rust
|
||||
|
||||
Rust is a modern systems programming language focusing on safety and speed. It
|
||||
accomplishes these goals by being memory safe without using garbage collection.
|
||||
This introduction is now deprecated. Please see [the introduction to the book][intro].
|
||||
|
||||
This introduction will give you a rough idea of what Rust is like, eliding many
|
||||
details. It does not require prior experience with systems programming, but you
|
||||
may find the syntax easier if you've used a "curly brace" programming language
|
||||
before, like C or JavaScript. The concepts are more important than the syntax,
|
||||
so don't worry if you don't get every last detail: you can read [The
|
||||
Rust Programming Language](book/index.html) to get a more complete explanation.
|
||||
|
||||
Because this is about high-level concepts, you don't need to actually install
|
||||
Rust to follow along. If you'd like to anyway, check out [the
|
||||
homepage](http://rust-lang.org) for explanation.
|
||||
|
||||
To show off Rust, let's talk about how easy it is to get started with Rust.
|
||||
Then, we'll talk about Rust's most interesting feature, *ownership*, and
|
||||
then discuss how it makes concurrency easier to reason about. Finally,
|
||||
we'll talk about how Rust breaks down the perceived dichotomy between speed
|
||||
and safety.
|
||||
|
||||
# Tools
|
||||
|
||||
Getting started on a new Rust project is incredibly easy, thanks to Rust's
|
||||
package manager, [Cargo](http://crates.io).
|
||||
|
||||
To start a new project with Cargo, use `cargo new`:
|
||||
|
||||
```{bash}
|
||||
$ cargo new hello_world --bin
|
||||
```
|
||||
|
||||
We're passing `--bin` because we're making a binary program: if we
|
||||
were making a library, we'd leave it off.
|
||||
|
||||
Let's check out what Cargo has generated for us:
|
||||
|
||||
```{bash}
|
||||
$ cd hello_world
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── main.rs
|
||||
|
||||
1 directory, 2 files
|
||||
```
|
||||
|
||||
This is all we need to get started. First, let's check out `Cargo.toml`:
|
||||
|
||||
```{toml}
|
||||
[package]
|
||||
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
This is called a *manifest*, and it contains all of the metadata that Cargo
|
||||
needs to compile your project.
|
||||
|
||||
Here's what's in `src/main.rs`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
Cargo generated a "Hello World" for us. We'll talk more about the syntax here
|
||||
later, but that's what Rust code looks like! Let's compile and run it:
|
||||
|
||||
```{bash}
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
Running `target/hello_world`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Using an external dependency in Rust is incredibly easy. You add a line to
|
||||
your `Cargo.toml`:
|
||||
|
||||
```{toml}
|
||||
[package]
|
||||
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
authors = ["Your Name <someone@example.com>"]
|
||||
|
||||
[dependencies.semver]
|
||||
|
||||
git = "https://github.com/rust-lang/semver.git"
|
||||
```
|
||||
|
||||
You added the `semver` library, which parses version numbers and compares them
|
||||
according to the [SemVer specification](http://semver.org/).
|
||||
|
||||
Now, you can pull in that library using `extern crate` in
|
||||
`main.rs`.
|
||||
|
||||
```{rust,ignore}
|
||||
extern crate semver;
|
||||
|
||||
use semver::Version;
|
||||
|
||||
fn main() {
|
||||
assert!(Version::parse("1.2.3") == Ok(Version {
|
||||
major: 1u64,
|
||||
minor: 2u64,
|
||||
patch: 3u64,
|
||||
pre: vec!(),
|
||||
build: vec!(),
|
||||
}));
|
||||
|
||||
println!("Versions compared successfully!");
|
||||
}
|
||||
```
|
||||
|
||||
Again, we'll discuss the exact details of all of this syntax soon. For now,
|
||||
let's compile and run it:
|
||||
|
||||
```{bash}
|
||||
$ cargo run
|
||||
Updating git repository `https://github.com/rust-lang/semver.git`
|
||||
Compiling semver v0.0.1 (https://github.com/rust-lang/semver.git#bf739419)
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
Running `target/hello_world`
|
||||
Versions compared successfully!
|
||||
```
|
||||
|
||||
Because we only specified a repository without a version, if someone else were
|
||||
to try out our project at a later date, when `semver` was updated, they would
|
||||
get a different, possibly incompatible version. To solve this problem, Cargo
|
||||
produces a file, `Cargo.lock`, which records the versions of any dependencies.
|
||||
This gives us repeatable builds.
|
||||
|
||||
There is a lot more here, and this is a whirlwind tour, but you should feel
|
||||
right at home if you've used tools like [Bundler](http://bundler.io/),
|
||||
[npm](https://www.npmjs.org/), or [pip](https://pip.pypa.io/en/latest/).
|
||||
There's no `Makefile`s or endless `autotools` output here. (Rust's tooling does
|
||||
[play nice with external libraries written in those
|
||||
tools](http://doc.crates.io/build-script.html), if you need to.)
|
||||
|
||||
Enough about tools, let's talk code!
|
||||
|
||||
# Ownership
|
||||
|
||||
Rust's defining feature is "memory safety without garbage collection". Let's
|
||||
take a moment to talk about what that means. *Memory safety* means that the
|
||||
programming language eliminates certain kinds of bugs, such as [buffer
|
||||
overflows](http://en.wikipedia.org/wiki/Buffer_overflow) and [dangling
|
||||
pointers](http://en.wikipedia.org/wiki/Dangling_pointer). These problems occur
|
||||
when you have unrestricted access to memory. As an example, here's some Ruby
|
||||
code:
|
||||
|
||||
```{ruby}
|
||||
v = []
|
||||
|
||||
v.push("Hello")
|
||||
|
||||
x = v[0]
|
||||
|
||||
v.push("world")
|
||||
|
||||
puts x
|
||||
```
|
||||
|
||||
We make an array, `v`, and then call `push` on it. `push` is a method which
|
||||
adds an element to the end of an array.
|
||||
|
||||
Next, we make a new variable, `x`, that's equal to the first element of
|
||||
the array. Simple, but this is where the "bug" will appear.
|
||||
|
||||
Let's keep going. We then call `push` again, pushing "world" onto the
|
||||
end of the array. `v` now is `["Hello", "world"]`.
|
||||
|
||||
Finally, we print `x` with the `puts` method. This prints "Hello."
|
||||
|
||||
All good? Let's go over a similar, but subtly different example, in C++:
|
||||
|
||||
```{cpp}
|
||||
#include<iostream>
|
||||
#include<vector>
|
||||
#include<string>
|
||||
|
||||
int main() {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back("Hello");
|
||||
|
||||
std::string& x = v[0];
|
||||
|
||||
v.push_back("world");
|
||||
|
||||
std::cout << x;
|
||||
}
|
||||
```
|
||||
|
||||
It's a little more verbose due to the static typing, but it's almost the same
|
||||
thing. We make a `std::vector` of `std::string`s, we call `push_back` (same as
|
||||
`push`) on it, take a reference to the first element of the vector, call
|
||||
`push_back` again, and then print out the reference.
|
||||
|
||||
There's two big differences here: one, they're not _exactly_ the same thing,
|
||||
and two...
|
||||
|
||||
```{bash}
|
||||
$ g++ hello.cpp -Wall -Werror
|
||||
$ ./a.out
|
||||
Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
A crash! (Note that this is actually system-dependent. Because referring to an
|
||||
invalid reference is undefined behavior, the compiler can do anything,
|
||||
including the right thing!) Even though we compiled with flags to give us as
|
||||
many warnings as possible, and to treat those warnings as errors, we got no
|
||||
errors. When we ran the program, it crashed.
|
||||
|
||||
Why does this happen? When we append to an array, its length changes. Since
|
||||
its length changes, we may need to allocate more memory. In Ruby, this happens
|
||||
as well, we just don't think about it very often. So why does the C++ version
|
||||
segfault when we allocate more memory?
|
||||
|
||||
The answer is that in the C++ version, `x` is a *reference* to the memory
|
||||
location where the first element of the array is stored. But in Ruby, `x` is a
|
||||
standalone value, not connected to the underlying array at all. Let's dig into
|
||||
the details for a moment. Your program has access to memory, provided to it by
|
||||
the operating system. Each location in memory has an address. So when we make
|
||||
our vector, `v`, it's stored in a memory location somewhere:
|
||||
|
||||
| location | name | value |
|
||||
|----------|------|-------|
|
||||
| 0x30 | v | |
|
||||
|
||||
(Address numbers made up, and in hexadecimal. Those of you with deep C++
|
||||
knowledge, there are some simplifications going on here, like the lack of an
|
||||
allocated length for the vector. This is an introduction.)
|
||||
|
||||
When we push our first string onto the array, we allocate some memory,
|
||||
and `v` refers to it:
|
||||
|
||||
| location | name | value |
|
||||
|----------|------|----------|
|
||||
| 0x30 | v | 0x18 |
|
||||
| 0x18 | | "Hello" |
|
||||
|
||||
We then make a reference to that first element. A reference is a variable
|
||||
that points to a memory location, so its value is the memory location of
|
||||
the `"Hello"` string:
|
||||
|
||||
| location | name | value |
|
||||
|----------|------|----------|
|
||||
| 0x30 | v | 0x18 |
|
||||
| 0x18 | | "Hello" |
|
||||
| 0x14 | x | 0x18 |
|
||||
|
||||
When we push `"world"` onto the vector with `push_back`, there's no room:
|
||||
we only allocated one element. So, we need to allocate two elements,
|
||||
copy the `"Hello"` string over, and update the reference. Like this:
|
||||
|
||||
| location | name | value |
|
||||
|----------|------|----------|
|
||||
| 0x30 | v | 0x08 |
|
||||
| 0x18 | | GARBAGE |
|
||||
| 0x14 | x | 0x18 |
|
||||
| 0x08 | | "Hello" |
|
||||
| 0x04 | | "world" |
|
||||
|
||||
Note that `v` now refers to the new list, which has two elements. It's all
|
||||
good. But our `x` didn't get updated! It still points at the old location,
|
||||
which isn't valid anymore. In fact, [the documentation for `push_back` mentions
|
||||
this](http://en.cppreference.com/w/cpp/container/vector/push_back):
|
||||
|
||||
> If the new `size()` is greater than `capacity()` then all iterators and
|
||||
> references (including the past-the-end iterator) are invalidated.
|
||||
|
||||
Finding where these iterators and references are is a difficult problem, and
|
||||
even in this simple case, `g++` can't help us here. While the bug is obvious in
|
||||
this case, in real code, it can be difficult to track down the source of the
|
||||
error.
|
||||
|
||||
Before we talk about this solution, why didn't our Ruby code have this problem?
|
||||
The semantics are a little more complicated, and explaining Ruby's internals is
|
||||
out of the scope of a guide to Rust. But in a nutshell, Ruby's garbage
|
||||
collector keeps track of references, and makes sure that everything works as
|
||||
you might expect. This comes at an efficiency cost, and the internals are more
|
||||
complex. If you'd really like to dig into the details, [this
|
||||
article](http://patshaughnessy.net/2012/1/18/seeing-double-how-ruby-shares-string-values)
|
||||
can give you more information.
|
||||
|
||||
Garbage collection is a valid approach to memory safety, but Rust chooses a
|
||||
different path. Let's examine what the Rust version of this looks like:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let mut v = vec![];
|
||||
|
||||
v.push("Hello");
|
||||
|
||||
let x = &v[0];
|
||||
|
||||
v.push("world");
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
This looks like a bit of both: fewer type annotations, but we do create new
|
||||
variables with `let`. The method name is `push`, some other stuff is different,
|
||||
but it's pretty close. So what happens when we compile this code? Does Rust
|
||||
print `"Hello"`, or does Rust crash?
|
||||
|
||||
Neither. It refuses to compile:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
main.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
main.rs:8 v.push("world");
|
||||
^
|
||||
main.rs:6:14: 6:15 note: previous borrow of `v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `v` until the borrow ends
|
||||
main.rs:6 let x = &v[0];
|
||||
^
|
||||
main.rs:11:2: 11:2 note: previous borrow ends here
|
||||
main.rs:1 fn main() {
|
||||
...
|
||||
main.rs:11 }
|
||||
^
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
When we try to mutate the array by `push`ing it the second time, Rust throws
|
||||
an error. It says that we "cannot borrow v as mutable because it is also
|
||||
borrowed as immutable." What does it mean by "borrowed"?
|
||||
|
||||
In Rust, the type system encodes the notion of *ownership*. The variable `v`
|
||||
is an *owner* of the vector. When we make a reference to `v`, we let that
|
||||
variable (in this case, `x`) *borrow* it for a while. Just like if you own a
|
||||
book, and you lend it to me, I'm borrowing the book.
|
||||
|
||||
So, when I try to modify the vector with the second call to `push`, I need
|
||||
to be owning it. But `x` is borrowing it. You can't modify something that
|
||||
you've lent to someone. And so Rust throws an error.
|
||||
|
||||
So how do we fix this problem? Well, we can make a copy of the element:
|
||||
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let mut v = vec![];
|
||||
|
||||
v.push("Hello");
|
||||
|
||||
let x = v[0].clone();
|
||||
|
||||
v.push("world");
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Note the addition of `clone()`. This creates a copy of the element, leaving
|
||||
the original untouched. Now, we no longer have two references to the same
|
||||
memory, and so the compiler is happy. Let's give that a try:
|
||||
|
||||
```{bash}
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
Running `target/hello_world`
|
||||
Hello
|
||||
```
|
||||
|
||||
Same result. Now, making a copy can be inefficient, so this solution may not be
|
||||
acceptable. There are other ways to get around this problem, but this is a toy
|
||||
example, and because we're in an introduction, we'll leave that for later.
|
||||
|
||||
The point is, the Rust compiler and its notion of ownership has saved us from a
|
||||
bug that would crash the program. We've achieved safety, at compile time,
|
||||
without needing to rely on a garbage collector to handle our memory.
|
||||
|
||||
# Concurrency
|
||||
|
||||
Rust's ownership model can help in other ways, as well. For example, take
|
||||
concurrency. Concurrency is a big topic, and an important one for any modern
|
||||
programming language. Let's take a look at how ownership can help you write
|
||||
safe concurrent programs.
|
||||
|
||||
Here's an example of a concurrent Rust program:
|
||||
|
||||
```{rust}
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let guards: Vec<_> = (0..10).map(|_| {
|
||||
thread::scoped(|| {
|
||||
println!("Hello, world!");
|
||||
})
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
This program creates ten threads, which all print `Hello, world!`. The `scoped`
|
||||
function takes one argument, a closure, indicated by the double bars `||`. This
|
||||
closure is executed in a new thread created by `scoped`. The method is called
|
||||
`scoped` because it returns a 'join guard', which will automatically join the
|
||||
child thread when it goes out of scope. Because we `collect` these guards into
|
||||
a `Vec<T>`, and that vector goes out of scope at the end of our program, our
|
||||
program will wait for every thread to finish before finishing.
|
||||
|
||||
One common form of problem in concurrent programs is a *data race*.
|
||||
This occurs when two different threads attempt to access the same
|
||||
location in memory in a non-synchronized way, where at least one of
|
||||
them is a write. If one thread is attempting to read, and one thread
|
||||
is attempting to write, you cannot be sure that your data will not be
|
||||
corrupted. Note the first half of that requirement: two threads that
|
||||
attempt to access the same location in memory. Rust's ownership model
|
||||
can track which pointers own which memory locations, which solves this
|
||||
problem.
|
||||
|
||||
Let's see an example. This Rust code will not compile:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let mut numbers = vec![1, 2, 3];
|
||||
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
thread::scoped(move || {
|
||||
numbers[i] += 1;
|
||||
println!("numbers[{}] is {}", i, numbers[i]);
|
||||
})
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
It gives us this error:
|
||||
|
||||
```text
|
||||
7:25: 10:6 error: cannot move out of captured outer variable in an `FnMut` closure
|
||||
7 thread::scoped(move || {
|
||||
8 numbers[i] += 1;
|
||||
9 println!("numbers[{}] is {}", i, numbers[i]);
|
||||
10 })
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
This is a little confusing because there are two closures here: the one passed
|
||||
to `map`, and the one passed to `thread::scoped`. In this case, the closure for
|
||||
`thread::scoped` is attempting to reference `numbers`, a `Vec<i32>`. This
|
||||
closure is a `FnOnce` closure, as that’s what `thread::scoped` takes as an
|
||||
argument. `FnOnce` closures take ownership of their environment. That’s fine,
|
||||
but there’s one detail: because of `map`, we’re going to make three of these
|
||||
closures. And since all three try to take ownership of `numbers`, that would be
|
||||
a problem. That’s what it means by ‘cannot move out of captured outer
|
||||
variable’: our `thread::scoped` closure wants to take ownership, and it can’t,
|
||||
because the closure for `map` won’t let it.
|
||||
|
||||
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
|
||||
*Arc* stands for "atomically reference counted". In other words, an Arc will
|
||||
keep track of the number of references to something, and not free the
|
||||
associated resource until the count is zero. The *atomic* portion refers to an
|
||||
Arc's usage of concurrency primitives to atomically update the count, making it
|
||||
safe across threads. If we use an Arc, we can have our three references. But,
|
||||
an Arc does not allow mutable borrows of the data it holds, and we want to
|
||||
modify what we're sharing. In this case, we can use a `Mutex<T>` inside of our
|
||||
Arc. A Mutex will synchronize our accesses, so that we can ensure that our
|
||||
mutation doesn't cause a data race.
|
||||
|
||||
Here's what using an Arc with a Mutex looks like:
|
||||
|
||||
```{rust}
|
||||
use std::thread;
|
||||
use std::sync::{Arc,Mutex};
|
||||
|
||||
fn main() {
|
||||
let numbers = Arc::new(Mutex::new(vec![1, 2, 3]));
|
||||
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
let number = numbers.clone();
|
||||
thread::scoped(move || {
|
||||
let mut array = number.lock().unwrap();
|
||||
array[i] += 1;
|
||||
println!("numbers[{}] is {}", i, array[i]);
|
||||
})
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
We first have to `use` the appropriate library, and then we wrap our vector in
|
||||
an Arc with the call to `Arc::new()`. Inside of the loop, we make a new
|
||||
reference to the Arc with the `clone()` method. This will increment the
|
||||
reference count. When each new `numbers` variable binding goes out of scope, it
|
||||
will decrement the count. The `lock()` call will return us a reference to the
|
||||
value inside the Mutex, and block any other calls to `lock()` until said
|
||||
reference goes out of scope.
|
||||
|
||||
We can compile and run this program without error, and in fact, see the
|
||||
non-deterministic aspect:
|
||||
|
||||
```{shell}
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
Running `target/hello_world`
|
||||
numbers[1] is 3
|
||||
numbers[0] is 2
|
||||
numbers[2] is 4
|
||||
$ cargo run
|
||||
Running `target/hello_world`
|
||||
numbers[2] is 4
|
||||
numbers[1] is 3
|
||||
numbers[0] is 2
|
||||
```
|
||||
|
||||
Each time, we can get a slightly different output because the threads are not
|
||||
guaranteed to run in any set order. If you get the same order every time it is
|
||||
because each of these threads are very small and complete too fast for their
|
||||
indeterminate behavior to surface.
|
||||
|
||||
The important part here is that the Rust compiler was able to use ownership to
|
||||
give us assurance _at compile time_ that we weren't doing something incorrect
|
||||
with regards to concurrency. In order to share ownership, we were forced to be
|
||||
explicit and use a mechanism to ensure that it would be properly handled.
|
||||
|
||||
# Safety _and_ Speed
|
||||
|
||||
Safety and speed are always presented as a continuum. At one end of the spectrum,
|
||||
you have maximum speed, but no safety. On the other end, you have absolute safety
|
||||
with no speed. Rust seeks to break out of this paradigm by introducing safety at
|
||||
compile time, ensuring that you haven't done anything wrong, while compiling to
|
||||
the same low-level code you'd expect without the safety.
|
||||
|
||||
As an example, Rust's ownership system is _entirely_ at compile time. The
|
||||
safety check that makes this an error about moved values:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let numbers = vec![1, 2, 3];
|
||||
|
||||
let guards: Vec<_> = (0..3).map(|i| {
|
||||
thread::scoped(move || {
|
||||
println!("{}", numbers[i]);
|
||||
})
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
carries no runtime penalty. And while some of Rust's safety features do have
|
||||
a run-time cost, there's often a way to write your code in such a way that
|
||||
you can remove it. As an example, this is a poor way to iterate through
|
||||
a vector:
|
||||
|
||||
```{rust}
|
||||
let vec = vec![1, 2, 3];
|
||||
|
||||
for i in 0..vec.len() {
|
||||
println!("{}", vec[i]);
|
||||
}
|
||||
```
|
||||
|
||||
The reason is that the access of `vec[i]` does bounds checking, to ensure
|
||||
that we don't try to access an invalid index. However, we can remove this
|
||||
while retaining safety. The answer is iterators:
|
||||
|
||||
```{rust}
|
||||
let vec = vec![1, 2, 3];
|
||||
|
||||
for x in &vec {
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
This version uses an iterator that yields each element of the vector in turn.
|
||||
Because we have a reference to the element, rather than the whole vector itself,
|
||||
there's no array access bounds to check.
|
||||
|
||||
# Learning More
|
||||
|
||||
I hope that this taste of Rust has given you an idea if Rust is the right
|
||||
language for you. We talked about Rust's tooling, how encoding ownership into
|
||||
the type system helps you find bugs, how Rust can help you write correct
|
||||
concurrent code, and how you don't have to pay a speed cost for much of this
|
||||
safety.
|
||||
|
||||
To continue your Rustic education, read [The Rust Programming
|
||||
Language](book/index.html) for a more in-depth exploration of Rust's syntax and
|
||||
concepts.
|
||||
[intro]: book/README.html
|
||||
|
@ -3788,7 +3788,7 @@ its type parameters are types:
|
||||
|
||||
```ignore
|
||||
fn map<A: Clone, B: Clone>(f: |A| -> B, xs: &[A]) -> Vec<B> {
|
||||
if xs.len() == 0 {
|
||||
if xs.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
let first: B = f(xs[0].clone());
|
||||
|
@ -1,10 +1,10 @@
|
||||
% Unit testing
|
||||
|
||||
Unit tests should live in a `test` submodule at the bottom of the module they
|
||||
test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when
|
||||
Unit tests should live in a `tests` submodule at the bottom of the module they
|
||||
test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
|
||||
testing.
|
||||
|
||||
The `test` module should contain:
|
||||
The `tests` module should contain:
|
||||
|
||||
* Imports needed only for testing.
|
||||
* Functions marked with `#[test]` striving for full coverage of the parent module's
|
||||
@ -17,7 +17,7 @@ For example:
|
||||
// Excerpt from std::str
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
assert!((eq(&"".to_owned(), &"".to_owned())));
|
||||
|
@ -1,39 +1,192 @@
|
||||
% The Rust Programming Language
|
||||
|
||||
Welcome! This book will teach you about [the Rust Programming
|
||||
Language](http://www.rust-lang.org/). Rust is a modern systems programming
|
||||
language focusing on safety and speed. It accomplishes these goals by being
|
||||
memory safe without using garbage collection.
|
||||
Welcome! This book will teach you about the [Rust Programming Language][rust].
|
||||
Rust is a systems programming language focused on three goals: safety, speed,
|
||||
and concurrency. It maintains these goals without having a garbage collector,
|
||||
making it a useful language for a number of use cases other languages aren’t
|
||||
good at: embedding in other languages, programs with specific space and time
|
||||
requirements, and writing low-level code, like device drivers and operating
|
||||
systems. It improves on current languages targeting this space by having a
|
||||
number of compile-time safety checks that produce no runtime overhead, while
|
||||
eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’
|
||||
even though some of these abstractions feel like those of a high-level
|
||||
language. Even then, Rust still allows precise control like a low-level
|
||||
language would.
|
||||
|
||||
"The Rust Programming Language" is split into three sections, which you can
|
||||
navigate through the menu on the left.
|
||||
[rust]: http://rust-lang.org
|
||||
|
||||
<h2 class="section-header"><a href="basic.html">Basics</a></h2>
|
||||
“The Rust Programming Language” is split into seven sections. This introduction
|
||||
is the first. After this:
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax.
|
||||
* [Getting started][gs] - Set up your computer for Rust development.
|
||||
* [Learn Rust][lr] - Learn Rust programming through small projects.
|
||||
* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code.
|
||||
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
|
||||
* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
|
||||
* [Glossary][gl] - A reference of terms used in the book.
|
||||
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
||||
[gs]: getting-started.html
|
||||
[lr]: learn-rust.html
|
||||
[er]: effective-rust.html
|
||||
[ss]: syntax-and-semantics.html
|
||||
[nr]: nightly-rust.html
|
||||
[gl]: glossary.html
|
||||
|
||||
<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
|
||||
After reading this introduction, you’ll want to dive into either ‘Learn Rust’
|
||||
or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
|
||||
want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to
|
||||
start small, and learn a single concept thoroughly before moving onto the next.
|
||||
Copious cross-linking connects these parts together.
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
## A brief introduction to Rust
|
||||
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
||||
Is Rust a language you might be interested in? Let’s examine a few small code
|
||||
samples to show off a few of its strengths.
|
||||
|
||||
<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
|
||||
The main concept that makes Rust unique is called ‘ownership’. Consider this
|
||||
small example:
|
||||
|
||||
In a similar fashion to "Intermediate," this section is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
chapters focus on the most complex features,
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
}
|
||||
```
|
||||
|
||||
<h2 class="section-header"><a href="unstable.html">Unstable</a></h2>
|
||||
This program makes a [variable binding][var] named `x`. The value of this
|
||||
binding is a `Vec<T>`, a ‘vector’, that we create through a [macro][macro]
|
||||
defined in the standard library. This macro is called `vec`, and we invoke
|
||||
macros with a `!`. This follows a general principle of Rust: make things
|
||||
explicit. Macros can do significantly more complicated things than function
|
||||
calls, and so they’re visually distinct. The `!` also helps with parsing,
|
||||
making tooling easier to write, which is also important.
|
||||
|
||||
In a similar fashion to "Intermediate," this section is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order.
|
||||
We used `mut` to make `x` mutable: bindings are immutable by default in Rust.
|
||||
We’ll be mutating this vector later in the example.
|
||||
|
||||
This chapter contains things that are only available on the nightly channel of
|
||||
Rust.
|
||||
It’s also worth noting that we didn’t need a type annotation here: while Rust
|
||||
is statically typed, we didn’t need to explicitly annotate the type. Rust has
|
||||
type inference to balance out the power of static typing with the verbosity of
|
||||
annotating types.
|
||||
|
||||
Rust prefers stack allocation to heap allocation: `x` is placed directly on the
|
||||
stack. However, the `Vec<T>` type allocates space for the elements of the
|
||||
vector on the heap. If you’re not familiar with this distinction, you can
|
||||
ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems
|
||||
programming language, Rust gives you the ability to control how your memory is
|
||||
allocated, but when we’re getting started, it’s less of a big deal.
|
||||
|
||||
[var]: variable-bindings.html
|
||||
[macro]: macros.html
|
||||
[heap]: the-stack-and-the-heap.html
|
||||
|
||||
Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust
|
||||
parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of
|
||||
scope, the vector’s memory will be de-allocated. This is done deterministically
|
||||
by the Rust compiler, rather than through a mechanism such as a garbage
|
||||
collector. In other words, in Rust, you don’t call functions like `malloc` and
|
||||
`free` yourself: the compiler statically determines when you need to allocate
|
||||
or deallocate memory, and inserts those calls itself. To err is to be human,
|
||||
but compilers never forget.
|
||||
|
||||
Let’s add another line to our example:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
|
||||
let y = &x[0];
|
||||
}
|
||||
```
|
||||
|
||||
We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to
|
||||
the first element of the vector. Rust’s references are similar to pointers in
|
||||
other languages, but with additional compile-time safety checks. References
|
||||
interact with the ownership system by [‘borrowing’][borrowing] what they point
|
||||
to, rather than owning it. The difference is, when the reference goes out of
|
||||
scope, it will not deallocate the underlying memory. If it did, we’d
|
||||
de-allocate twice, which is bad!
|
||||
|
||||
[borrowing]: references-and-borrowing.html
|
||||
|
||||
Let’s add a third line. It looks innocent enough, but causes a compiler error:
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
|
||||
let y = &x[0];
|
||||
|
||||
x.push("foo");
|
||||
}
|
||||
```
|
||||
|
||||
`push` is a method on vectors that appends another element to the end of the
|
||||
vector. When we try to compile this program, we get an error:
|
||||
|
||||
```text
|
||||
error: cannot borrow `x` as mutable because it is also borrowed as immutable
|
||||
x.push(4);
|
||||
^
|
||||
note: previous borrow of `x` occurs here; the immutable borrow prevents
|
||||
subsequent moves or mutable borrows of `x` until the borrow ends
|
||||
let y = &x[0];
|
||||
^
|
||||
note: previous borrow ends here
|
||||
fn main() {
|
||||
|
||||
}
|
||||
^
|
||||
```
|
||||
|
||||
Whew! The Rust compiler gives quite detailed errors at times, and this is one
|
||||
of those times. As the error explains, while we made our binding mutable, we
|
||||
still cannot call `push`. This is because we already have a reference to an
|
||||
element of the vector, `y`. Mutating something while another reference exists
|
||||
is dangerous, because we may invalidate the reference. In this specific case,
|
||||
when we create the vector, we may have only allocated space for three elements.
|
||||
Adding a fourth would mean allocating a new chunk of memory for all those elements,
|
||||
copying the old values over, and updating the internal pointer to that memory.
|
||||
That all works just fine. The problem is that `y` wouldn’t get updated, and so
|
||||
we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in
|
||||
this case, and so the compiler has caught this for us.
|
||||
|
||||
So how do we solve this problem? There are two approaches we can take. The first
|
||||
is making a copy rather than using a reference:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
|
||||
let y = x[0].clone();
|
||||
|
||||
x.push("foo");
|
||||
}
|
||||
```
|
||||
|
||||
Rust has [move semantics][move] by default, so if we want to make a copy of some
|
||||
data, we call the `clone()` method. In this example, `y` is no longer a reference
|
||||
to the vector stored in `x`, but a copy of its first element, `"hello"`. Now
|
||||
that we don’t have a reference, our `push()` works just fine.
|
||||
|
||||
[move]: move-semantics.html
|
||||
|
||||
If we truly want a reference, we need the other option: ensure that our reference
|
||||
goes out of scope before we try to do the mutation. That looks like this:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = vec!["Hello", "world"];
|
||||
|
||||
{
|
||||
let y = &x[0];
|
||||
}
|
||||
|
||||
x.push("foo");
|
||||
}
|
||||
```
|
||||
|
||||
We created an inner scope with an additional set of curly braces. `y` will go out of
|
||||
scope before we call `push()`, and so we’re all good.
|
||||
|
||||
This concept of ownership isn’t just good for preventing danging pointers, but an
|
||||
entire set of related problems, like iterator invalidation, concurrency, and more.
|
||||
|
@ -1,42 +1,62 @@
|
||||
# Summary
|
||||
|
||||
* [The Basics](basic.md)
|
||||
* [Getting Started](getting-started.md)
|
||||
* [Installing Rust](installing-rust.md)
|
||||
* [Hello, world!](hello-world.md)
|
||||
* [Hello, Cargo!](hello-cargo.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [If](if.md)
|
||||
* [Functions](functions.md)
|
||||
* [Comments](comments.md)
|
||||
* [Compound Data Types](compound-data-types.md)
|
||||
* [Match](match.md)
|
||||
* [Looping](looping.md)
|
||||
* [Strings](strings.md)
|
||||
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
|
||||
* [Intermediate Rust](intermediate.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [Learn Rust](learn-rust.md)
|
||||
* [Effective Rust](effective-rust.md)
|
||||
* [The Stack and the Heap](the-stack-and-the-heap.md)
|
||||
* [Debug and Display](debug-and-display.md)
|
||||
* [Testing](testing.md)
|
||||
* [Pointers](pointers.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [More Strings](more-strings.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
* [Closures](closures.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md)
|
||||
* [Macros](macros.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
* [Advanced Macros](advanced-macros.md)
|
||||
* [Unstable Rust](unstable.md)
|
||||
* [Compiler Plugins](plugins.md)
|
||||
* [Deref coercions](deref-coercions.md)
|
||||
* [Syntax and Semantics](syntax-and-semantics.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [Functions](functions.md)
|
||||
* [Primitive Types](primitive-types.md)
|
||||
* [Comments](comments.md)
|
||||
* [if](if.md)
|
||||
* [for loops](for-loops.md)
|
||||
* [while loops](while-loops.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [References and Borrowing](references-and-borrowing.md)
|
||||
* [Lifetimes](lifetimes.md)
|
||||
* [Mutability](mutability.md)
|
||||
* [Move semantics](move-semantics.md)
|
||||
* [Enums](enums.md)
|
||||
* [Match](match.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Structs](structs.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Drop](drop.md)
|
||||
* [Vectors](vectors.md)
|
||||
* [Strings](strings.md)
|
||||
* [Traits](traits.md)
|
||||
* [Operators and Overloading](operators-and-overloading.md)
|
||||
* [Generics](generics.md)
|
||||
* [if let](if-let.md)
|
||||
* [Trait Objects](trait-objects.md)
|
||||
* [Closures](closures.md)
|
||||
* [Universal Function Call Syntax](ufcs.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [`static`](static.md)
|
||||
* [`const`](const.md)
|
||||
* [Tuple Structs](tuple-structs.md)
|
||||
* [Attributes](attributes.md)
|
||||
* [Conditional Compilation](conditional-compilation.md)
|
||||
* [`type` aliases](type-aliases.md)
|
||||
* [Casting between types](casting-between-types.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
* [Unsized Types](unsized-types.md)
|
||||
* [Macros](macros.md)
|
||||
* [`unsafe` Code](unsafe-code.md)
|
||||
* [Nightly Rust](nightly-rust.md)
|
||||
* [Compiler Plugins](compiler-plugins.md)
|
||||
* [Inline Assembly](inline-assembly.md)
|
||||
* [No stdlib](no-stdlib.md)
|
||||
* [Intrinsics](intrinsics.md)
|
||||
@ -44,5 +64,6 @@
|
||||
* [Link args](link-args.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
|
||||
* [Conclusion](conclusion.md)
|
||||
* [Slice Patterns](slice-patterns.md)
|
||||
* [Glossary](glossary.md)
|
||||
* [Academic Research](academic-research.md)
|
||||
|
46
src/doc/trpl/academic-research.md
Normal file
46
src/doc/trpl/academic-research.md
Normal file
@ -0,0 +1,46 @@
|
||||
% Academic Research
|
||||
|
||||
An incomplete list of papers that have had some influence in Rust.
|
||||
|
||||
Recommended for inspiration and a better understanding of Rust's background.
|
||||
|
||||
### Type system
|
||||
|
||||
* [Region based memory management in Cyclone](http://209.68.42.137/ucsd-pages/Courses/cse227.w03/handouts/cyclone-regions.pdf)
|
||||
* [Safe manual memory management in Cyclone](http://www.cs.umd.edu/projects/PL/cyclone/scp.pdf)
|
||||
* [Typeclasses: making ad-hoc polymorphism less ad hoc](http://www.ps.uni-sb.de/courses/typen-ws99/class.ps.gz)
|
||||
* [Macros that work together](https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf)
|
||||
* [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf)
|
||||
* [Alias burying](http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps) - We tried something similar and abandoned it.
|
||||
* [External uniqueness is unique enough](http://www.computingscience.nl/research/techreps/repo/CS-2002/2002-048.pdf)
|
||||
* [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf)
|
||||
* [Region Based Memory Management](http://www.cs.ucla.edu/~palsberg/tba/papers/tofte-talpin-iandc97.pdf)
|
||||
|
||||
### Concurrency
|
||||
|
||||
* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf)
|
||||
* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf)
|
||||
* [Scheduling multithreaded computations by work stealing](http://supertech.csail.mit.edu/papers/steal.pdf)
|
||||
* [Thread scheduling for multiprogramming multiprocessors](http://www.eecis.udel.edu/%7Ecavazos/cisc879-spring2008/papers/arora98thread.pdf)
|
||||
* [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf)
|
||||
* [Dynamic circular work stealing deque](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf) - The Chase/Lev deque
|
||||
* [Work-first and help-first scheduling policies for async-finish task parallelism](http://www.cs.rice.edu/%7Eyguo/pubs/PID824943.pdf) - More general than fully-strict work stealing
|
||||
* [A Java fork/join calamity](http://www.coopsoft.com/ar/CalamityArticle.html) - critique of Java's fork/join library, particularly its application of work stealing to non-strict computation
|
||||
* [Scheduling techniques for concurrent systems](http://www.ece.rutgers.edu/%7Eparashar/Classes/ece572-papers/05/ps-ousterhout.pdf)
|
||||
* [Contention aware scheduling](http://www.blagodurov.net/files/a8-blagodurov.pdf)
|
||||
* [Balanced work stealing for time-sharing multicores](http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/papers/TR-12-1.pdf)
|
||||
* [Three layer cake](http://www.upcrc.illinois.edu/workshops/paraplop10/papers/paraplop10_submission_8.pdf)
|
||||
* [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
|
||||
* [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf)
|
||||
* [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf)
|
||||
|
||||
### Others
|
||||
|
||||
* [Crash-only software](https://www.usenix.org/legacy/events/hotos03/tech/full_papers/candea/candea.pdf)
|
||||
* [Composing High-Performance Memory Allocators](http://people.cs.umass.edu/~emery/pubs/berger-pldi2001.pdf)
|
||||
* [Reconsidering Custom Memory Allocation](http://people.cs.umass.edu/~emery/pubs/berger-oopsla2002.pdf)
|
||||
|
||||
### Papers *about* Rust
|
||||
|
||||
* [GPU programming in Rust](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf)
|
||||
* [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - not exactly about rust, but by nmatsakis
|
@ -1,242 +0,0 @@
|
||||
% Advanced macros
|
||||
|
||||
This chapter picks up where the [introductory macro chapter](macros.html) left
|
||||
off.
|
||||
|
||||
# Syntactic requirements
|
||||
|
||||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||
[syntax tree][ast]. This property can be very useful for editors and other
|
||||
tools that process code. It also has a few consequences for the design of
|
||||
Rust's macro system.
|
||||
|
||||
[ast]: glossary.html#abstract-syntax-tree
|
||||
|
||||
One consequence is that Rust must determine, when it parses a macro invocation,
|
||||
whether the macro stands in for
|
||||
|
||||
* zero or more items,
|
||||
* zero or more methods,
|
||||
* an expression,
|
||||
* a statement, or
|
||||
* a pattern.
|
||||
|
||||
A macro invocation within a block could stand for some items, or for an
|
||||
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
|
||||
macro invocation that stands for items must be either
|
||||
|
||||
* delimited by curly braces, e.g. `foo! { ... }`, or
|
||||
* terminated by a semicolon, e.g. `foo!(...);`
|
||||
|
||||
Another consequence of pre-expansion parsing is that the macro invocation must
|
||||
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
* `path`: a qualified name. Example: `T::SpecialA`.
|
||||
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
|
||||
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
|
||||
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
|
||||
* `stmt`: a single statement. Example: `let x = 3`.
|
||||
* `block`: a brace-delimited sequence of statements. Example:
|
||||
`{ log(error, "hi"); return 12; }`.
|
||||
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
|
||||
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
|
||||
* `tt`: a single token tree.
|
||||
|
||||
There are additional rules regarding the next token after a metavariable:
|
||||
|
||||
* `expr` variables must be followed by one of: `=> , ;`
|
||||
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
|
||||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
|
||||
be forced to choose between parsing `$t` and parsing `$e`. Changing the
|
||||
invocation syntax to put a distinctive token in front can solve the problem. In
|
||||
this case, you can write `$(T $t:ty)* E $e:exp`.
|
||||
|
||||
[item]: ../reference.html#items
|
||||
|
||||
# Scoping and macro import/export
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||
`$crate` is a single identifier.
|
||||
|
||||
# The deep end
|
||||
|
||||
The introductory chapter mentioned recursive macros, but it did not give the
|
||||
full story. Recursive macros are useful for another reason: Each recursive
|
||||
invocation gives you another opportunity to pattern-match the macro's
|
||||
arguments.
|
||||
|
||||
As an extreme example, it is possible, though hardly advisable, to implement
|
||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||
within Rust's macro system.
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
Exercise: use macros to reduce duplication in the above definition of the
|
||||
`bct!` macro.
|
||||
|
||||
# Procedural macros
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and bugs can be much harder to track down. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
@ -1,8 +0,0 @@
|
||||
% Advanced
|
||||
|
||||
In a similar fashion to "Intermediate," this section is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
chapters focus on the most complex features, as well as some things that
|
||||
are only available in upcoming versions of Rust.
|
||||
|
||||
After reading "Advanced," you'll be a Rust expert!
|
@ -1,102 +0,0 @@
|
||||
% Arrays, Vectors, and Slices
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the *array*, a fixed-size list of elements of the
|
||||
same type. By default, arrays are immutable.
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3]; // a: [i32; 3]
|
||||
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
||||
```
|
||||
|
||||
There's a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0`:
|
||||
|
||||
```{rust}
|
||||
let a = [0; 20]; // a: [i32; 20]
|
||||
```
|
||||
|
||||
Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we
|
||||
cover generics.
|
||||
|
||||
You can get the number of elements in an array `a` with `a.len()`, and use
|
||||
`a.iter()` to iterate over them with a for loop. This code will print each
|
||||
number in order:
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3];
|
||||
|
||||
println!("a has {} elements", a.len());
|
||||
for e in a.iter() {
|
||||
println!("{}", e);
|
||||
}
|
||||
```
|
||||
|
||||
You can access a particular element of an array with *subscript notation*:
|
||||
|
||||
```{rust}
|
||||
let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3]
|
||||
|
||||
println!("The second name is: {}", names[1]);
|
||||
```
|
||||
|
||||
Subscripts start at zero, like in most programming languages, so the first name
|
||||
is `names[0]` and the second name is `names[1]`. The above example prints
|
||||
`The second name is: Brian`. If you try to use a subscript that is not in the
|
||||
array, you will get an error: array access is bounds-checked at run-time. Such
|
||||
errant access is the source of many bugs in other systems programming
|
||||
languages.
|
||||
|
||||
A *vector* is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](../std/vec/) (we'll talk about what the `<T>` means
|
||||
later). Vectors always allocate their data on the heap. Vectors are to slices
|
||||
what `String` is to `&str`. You can create them with the `vec!` macro:
|
||||
|
||||
```{rust}
|
||||
let v = vec![1, 2, 3]; // v: Vec<i32>
|
||||
```
|
||||
|
||||
(Notice that unlike the `println!` macro we've used in the past, we use square
|
||||
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
|
||||
this is just convention.)
|
||||
|
||||
There's an alternate form of `vec!` for repeating an initial value:
|
||||
|
||||
```
|
||||
let v = vec![0; 10]; // ten zeroes
|
||||
```
|
||||
|
||||
You can get the length of, iterate over, and subscript vectors just like
|
||||
arrays. In addition, (mutable) vectors can grow automatically:
|
||||
|
||||
```{rust}
|
||||
let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
||||
|
||||
nums.push(4);
|
||||
|
||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||
```
|
||||
|
||||
Vectors have many more useful methods.
|
||||
|
||||
A *slice* is a reference to (or "view" into) an array. They are useful for
|
||||
allowing safe, efficient access to a portion of an array without copying. For
|
||||
example, you might want to reference just one line of a file read into memory.
|
||||
By nature, a slice is not created directly, but from an existing variable.
|
||||
Slices have a length, can be mutable or not, and in many ways behave like
|
||||
arrays:
|
||||
|
||||
```{rust}
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||
|
||||
for e in middle.iter() {
|
||||
println!("{}", e); // Prints 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
You can also take a slice of a vector, `String`, or `&str`, because they are
|
||||
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
|
||||
generics.
|
||||
|
||||
We have now learned all of the most basic Rust concepts.
|
@ -198,5 +198,5 @@ let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;
|
||||
```
|
||||
|
||||
The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N`
|
||||
type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we
|
||||
type parameter. Same with `E=Edge`. If we didn’t provide this constraint, we
|
||||
couldn’t be sure which `impl` to match this trait object to.
|
||||
|
3
src/doc/trpl/attributes.md
Normal file
3
src/doc/trpl/attributes.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Attributes
|
||||
|
||||
Coming Soon!
|
@ -1,7 +0,0 @@
|
||||
% Basics
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax.
|
||||
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
@ -13,7 +13,7 @@ pub fn add_two(a: i32) -> i32 {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod test {
|
||||
use super::*;
|
||||
use test::Bencher;
|
||||
|
||||
|
3
src/doc/trpl/casting-between-types.md
Normal file
3
src/doc/trpl/casting-between-types.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Casting Between Types
|
||||
|
||||
Coming Soon
|
@ -54,7 +54,7 @@ The second is that the syntax is similar, but a bit different. I've added spaces
|
||||
here to make them look a little closer:
|
||||
|
||||
```rust
|
||||
fn plus_one_v1 ( x: i32 ) -> i32 { x + 1 }
|
||||
fn plus_one_v1 (x: i32 ) -> i32 { x + 1 }
|
||||
let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
|
||||
let plus_one_v3 = |x: i32 | x + 1 ;
|
||||
```
|
||||
@ -175,9 +175,6 @@ we called `add_num`, it mutated the underlying value, as we'd expect. We also
|
||||
needed to declare `add_num` as `mut` too, because we’re mutating its
|
||||
environment.
|
||||
|
||||
We also had to declare `add_num` as mut, since we will be modifying its
|
||||
environment.
|
||||
|
||||
If we change to a `move` closure, it's different:
|
||||
|
||||
```rust
|
||||
@ -208,11 +205,11 @@ you tons of control over what your code does, and closures are no different.
|
||||
|
||||
Rust's implementation of closures is a bit different than other languages. They
|
||||
are effectively syntax sugar for traits. You'll want to make sure to have read
|
||||
the [traits chapter][traits] before this one, as well as the chapter on [static
|
||||
and dynamic dispatch][dispatch], which talks about trait objects.
|
||||
the [traits chapter][traits] before this one, as well as the chapter on [trait
|
||||
objects][trait-objects].
|
||||
|
||||
[traits]: traits.html
|
||||
[dispatch]: static-and-dynamic-dispatch.html
|
||||
[trait-objects]: trait-objects.html
|
||||
|
||||
Got all that? Good.
|
||||
|
||||
|
@ -1,47 +1,45 @@
|
||||
% Comments
|
||||
|
||||
Now that we have some functions, it's a good idea to learn about comments.
|
||||
Now that we have some functions, it’s a good idea to learn about comments.
|
||||
Comments are notes that you leave to other programmers to help explain things
|
||||
about your code. The compiler mostly ignores them.
|
||||
|
||||
Rust has two kinds of comments that you should care about: *line comments*
|
||||
and *doc comments*.
|
||||
|
||||
```{rust}
|
||||
// Line comments are anything after '//' and extend to the end of the line.
|
||||
```rust
|
||||
// Line comments are anything after ‘//’ and extend to the end of the line.
|
||||
|
||||
let x = 5; // this is also a line comment.
|
||||
|
||||
// If you have a long explanation for something, you can put line comments next
|
||||
// to each other. Put a space between the // and your comment so that it's
|
||||
// to each other. Put a space between the // and your comment so that it’s
|
||||
// more readable.
|
||||
```
|
||||
|
||||
The other kind of comment is a doc comment. Doc comments use `///` instead of
|
||||
`//`, and support Markdown notation inside:
|
||||
|
||||
```{rust}
|
||||
/// `hello` is a function that prints a greeting that is personalized based on
|
||||
/// the name given.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name of the person you'd like to greet.
|
||||
```rust
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// let name = "Steve";
|
||||
/// hello(name); // prints "Hello, Steve!"
|
||||
/// ```
|
||||
fn hello(name: &str) {
|
||||
println!("Hello, {}!", name);
|
||||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, add_one(5));
|
||||
/// ```
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
When writing doc comments, adding sections for any arguments, return values,
|
||||
and providing some examples of usage is very, very helpful. Don't worry about
|
||||
the `&str`, we'll get to it soon.
|
||||
When writing doc comments, providing some examples of usage is very, very
|
||||
helpful. You’ll notice we’ve used a new macro here: `assert_eq!`. This compares
|
||||
two values, and `panic!`s if they’re not equal to each other. It’s very helpful
|
||||
in documentation. There’s another macro, `assert!`, which `panic!`s if the
|
||||
value passed to it is `false`.
|
||||
|
||||
You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation
|
||||
from these doc comments.
|
||||
from these doc comments, and also to run the code examples as tests!
|
||||
|
@ -1,364 +0,0 @@
|
||||
% Compound Data Types
|
||||
|
||||
Rust, like many programming languages, has a number of different data types
|
||||
that are built-in. You've already done some simple work with integers and
|
||||
strings, but next, let's talk about some more complicated ways of storing data.
|
||||
|
||||
## Tuples
|
||||
|
||||
The first compound data type we're going to talk about is called the *tuple*.
|
||||
A tuple is an ordered list of fixed size. Like this:
|
||||
|
||||
```rust
|
||||
let x = (1, "hello");
|
||||
```
|
||||
|
||||
The parentheses and commas form this two-length tuple. Here's the same code, but
|
||||
with the type annotated:
|
||||
|
||||
```rust
|
||||
let x: (i32, &str) = (1, "hello");
|
||||
```
|
||||
|
||||
As you can see, the type of a tuple looks just like the tuple, but with each
|
||||
position having a type name rather than the value. Careful readers will also
|
||||
note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
|
||||
You have briefly seen `&str` used as a type before, and we'll discuss the
|
||||
details of strings later. In systems programming languages, strings are a bit
|
||||
more complex than in other languages. For now, just read `&str` as a *string
|
||||
slice*, and we'll learn more soon.
|
||||
|
||||
You can access the fields in a tuple through a *destructuring let*. Here's
|
||||
an example:
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
||||
println!("x is {}", x);
|
||||
```
|
||||
|
||||
Remember before when I said the left-hand side of a `let` statement was more
|
||||
powerful than just assigning a binding? Here we are. We can put a pattern on
|
||||
the left-hand side of the `let`, and if it matches up to the right-hand side,
|
||||
we can assign multiple bindings at once. In this case, `let` "destructures,"
|
||||
or "breaks up," the tuple, and assigns the bits to three bindings.
|
||||
|
||||
This pattern is very powerful, and we'll see it repeated more later.
|
||||
|
||||
There are also a few things you can do with a tuple as a whole, without
|
||||
destructuring. You can assign one tuple into another, if they have the same
|
||||
contained types and [arity]. Tuples have the same arity when they have the same
|
||||
length.
|
||||
|
||||
```rust
|
||||
let mut x = (1, 2); // x: (i32, i32)
|
||||
let y = (2, 3); // y: (i32, i32)
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
You can also check for equality with `==`. Again, this will only compile if the
|
||||
tuples have the same type.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 2, 4);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
This will print `no`, because some of the values aren't equal.
|
||||
|
||||
Note that the order of the values is considered when checking for equality,
|
||||
so the following example will also print `no`.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 1, 3);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
One other use of tuples is to return multiple values from a function:
|
||||
|
||||
```rust
|
||||
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }
|
||||
|
||||
fn main() {
|
||||
let (x, y) = next_two(5);
|
||||
println!("x, y = {}, {}", x, y);
|
||||
}
|
||||
```
|
||||
|
||||
Even though Rust functions can only return one value, a tuple *is* one value,
|
||||
that happens to be made up of more than one value. You can also see in this
|
||||
example how you can destructure a pattern returned by a function, as well.
|
||||
|
||||
Tuples are a very simple data structure, and so are not often what you want.
|
||||
Let's move on to their bigger sibling, structs.
|
||||
|
||||
## Structs
|
||||
|
||||
A struct is another form of a *record type*, just like a tuple. There's a
|
||||
difference: structs give each element that they contain a name, called a
|
||||
*field* or a *member*. Check it out:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let origin = Point { x: 0, y: 0 }; // origin: Point
|
||||
|
||||
println!("The origin is at ({}, {})", origin.x, origin.y);
|
||||
}
|
||||
```
|
||||
|
||||
There's a lot going on here, so let's break it down. We declare a struct with
|
||||
the `struct` keyword, and then with a name. By convention, structs begin with a
|
||||
capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn't need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```{rust}
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
println!("The point is at ({}, {})", point.x, point.y);
|
||||
}
|
||||
```
|
||||
|
||||
This will print `The point is at (5, 0)`.
|
||||
|
||||
## Tuple Structs and Newtypes
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
||||
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
||||
it allows you to create a new type, distinct from that of its contained value
|
||||
and expressing its own semantic meaning:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
||||
|
||||
## Enums
|
||||
|
||||
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
|
||||
feature of Rust, and are used throughout the standard library. An `enum` is
|
||||
a type which relates a set of alternates to a specific name. For example, below
|
||||
we define `Character` to be either a `Digit` or something else. These
|
||||
can be used via their fully scoped names: `Character::Other` (more about `::`
|
||||
below).
|
||||
|
||||
```rust
|
||||
enum Character {
|
||||
Digit(i32),
|
||||
Other,
|
||||
}
|
||||
```
|
||||
|
||||
Most normal types are allowed as the variant components of an `enum`. Here are
|
||||
some examples:
|
||||
|
||||
```rust
|
||||
struct Empty;
|
||||
struct Color(i32, i32, i32);
|
||||
struct Length(i32);
|
||||
struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
|
||||
struct HeightDatabase(Vec<i32>);
|
||||
```
|
||||
|
||||
You see that, depending on its type, an `enum` variant may or may not hold data.
|
||||
In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
|
||||
value, where `Other` is only a name. However, the fact that they represent
|
||||
distinct categories of `Character` is a very useful property.
|
||||
|
||||
As with structures, the variants of an enum by default are not comparable with
|
||||
equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
|
||||
support other binary operations such as `*` and `+`. As such, the following code
|
||||
is invalid for the example `Character` type:
|
||||
|
||||
```{rust,ignore}
|
||||
// These assignments both succeed
|
||||
let ten = Character::Digit(10);
|
||||
let four = Character::Digit(4);
|
||||
|
||||
// Error: `*` is not implemented for type `Character`
|
||||
let forty = ten * four;
|
||||
|
||||
// Error: `<=` is not implemented for type `Character`
|
||||
let four_is_smaller = four <= ten;
|
||||
|
||||
// Error: `==` is not implemented for type `Character`
|
||||
let four_equals_ten = four == ten;
|
||||
```
|
||||
|
||||
This may seem rather limiting, but it's a limitation which we can overcome.
|
||||
There are two ways: by implementing equality ourselves, or by pattern matching
|
||||
variants with [`match`][match] expressions, which you'll learn in the next
|
||||
chapter. We don't know enough about Rust to implement equality yet, but we can
|
||||
use the `Ordering` enum from the standard library, which does:
|
||||
|
||||
```
|
||||
enum Ordering {
|
||||
Less,
|
||||
Equal,
|
||||
Greater,
|
||||
}
|
||||
```
|
||||
|
||||
Because `Ordering` has already been defined for us, we will import it with the
|
||||
`use` keyword. Here's an example of how it is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives
|
||||
in the `cmp` submodule of the `std` module. We'll talk more about modules later
|
||||
in the guide. For now, all you need to know is that you can `use` things from
|
||||
the standard library if you need them.
|
||||
|
||||
Okay, let's talk about the actual code in the example. `cmp` is a function that
|
||||
compares two things, and returns an `Ordering`. We return either
|
||||
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
|
||||
whether the first value is less than, greater than, or equal to the second. Note
|
||||
that each variant of the `enum` is namespaced under the `enum` itself: it's
|
||||
`Ordering::Greater`, not `Greater`.
|
||||
|
||||
The `ordering` variable has the type `Ordering`, and so contains one of the
|
||||
three values. We then do a bunch of `if`/`else` comparisons to check which
|
||||
one it is.
|
||||
|
||||
This `Ordering::Greater` notation is too long. Let's use another form of `use`
|
||||
to import the `enum` variants instead. This will avoid full scoping:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering::{self, Equal, Less, Greater};
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Less }
|
||||
else if a > b { Greater }
|
||||
else { Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Less { println!("less"); }
|
||||
else if ordering == Greater { println!("greater"); }
|
||||
else if ordering == Equal { println!("equal"); }
|
||||
}
|
||||
```
|
||||
|
||||
Importing variants is convenient and compact, but can also cause name conflicts,
|
||||
so do this with caution. For this reason, it's normally considered better style
|
||||
to `use` an enum rather than its variants directly.
|
||||
|
||||
As you can see, `enum`s are quite a powerful tool for data representation, and
|
||||
are even more useful when they're [generic][generics] across types. Before we
|
||||
get to generics, though, let's talk about how to use enums with pattern
|
||||
matching, a tool that will let us deconstruct sum types (the type theory term
|
||||
for enums) like `Ordering` in a very elegant way that avoids all these messy
|
||||
and brittle `if`/`else`s.
|
||||
|
||||
|
||||
[arity]: ./glossary.html#arity
|
||||
[match]: ./match.html
|
||||
[generics]: ./generics.html
|
@ -1,11 +0,0 @@
|
||||
% Conclusion
|
||||
|
||||
We covered a lot of ground here. When you've mastered everything in this Guide,
|
||||
you will have a firm grasp of Rust development. There's a whole lot more
|
||||
out there, though, we've just covered the surface. There's tons of topics that
|
||||
you can dig deeper into, e.g. by reading the API documentation of the
|
||||
[standard library](http://doc.rust-lang.org/std/), by discovering solutions for
|
||||
common problems on [Rust by Example](http://rustbyexample.com/), or by browsing
|
||||
crates written by the community on [crates.io](https://crates.io/).
|
||||
|
||||
Happy hacking!
|
@ -56,70 +56,34 @@ place!
|
||||
|
||||
## Threads
|
||||
|
||||
Rust's standard library provides a library for 'threads', which allow you to
|
||||
Rust's standard library provides a library for threads, which allow you to
|
||||
run Rust code in parallel. Here's a basic example of using `std::thread`:
|
||||
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The `thread::scoped()` method accepts a closure, which is executed in a new
|
||||
thread. It's called `scoped` because this thread returns a join guard:
|
||||
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let guard = thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
// guard goes out of scope here
|
||||
}
|
||||
```
|
||||
|
||||
When `guard` goes out of scope, it will block execution until the thread is
|
||||
finished. If we didn't want this behaviour, we could use `thread::spawn()`:
|
||||
|
||||
```
|
||||
# #![feature(old_io, std_misc)]
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
timer::sleep(Duration::milliseconds(50));
|
||||
}
|
||||
```
|
||||
|
||||
We need to `sleep` here because when `main()` ends, it kills all of the
|
||||
running threads.
|
||||
The `thread::spawn()` method accepts a closure, which is executed in a
|
||||
new thread. It returns a handle to the thread, that can be used to
|
||||
wait for the child thread to finish and extract its result:
|
||||
|
||||
[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting
|
||||
type signature:
|
||||
|
||||
```text
|
||||
fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T>
|
||||
where T: Send + 'a,
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'a
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
Specifically, `F`, the closure that we pass to execute in the new thread. It
|
||||
has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce`
|
||||
allows the closure to take ownership of any data it mentions from the parent
|
||||
thread. The other restriction is that `F` must be `Send`. We aren't allowed to
|
||||
transfer this ownership unless the type thinks that's okay.
|
||||
fn main() {
|
||||
let handle = thread::spawn(|| {
|
||||
"Hello from a thread!"
|
||||
});
|
||||
|
||||
println!("{}", handle.join().unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
Many languages have the ability to execute threads, but it's wildly unsafe.
|
||||
There are entire books about how to prevent errors that occur from shared
|
||||
@ -147,10 +111,7 @@ As an example, here is a Rust program that would have a data race in many
|
||||
languages. It will not compile:
|
||||
|
||||
```ignore
|
||||
# #![feature(old_io, std_misc)]
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let mut data = vec![1u32, 2, 3];
|
||||
@ -161,14 +122,14 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
timer::sleep(Duration::milliseconds(50));
|
||||
thread::sleep_ms(50);
|
||||
}
|
||||
```
|
||||
|
||||
This gives us an error:
|
||||
|
||||
```text
|
||||
12:17 error: capture of moved value: `data`
|
||||
8:17 error: capture of moved value: `data`
|
||||
data[i] += 1;
|
||||
^~~~
|
||||
```
|
||||
@ -187,10 +148,7 @@ only one person at a time can mutate what's inside. For that, we can use the
|
||||
but for a different reason:
|
||||
|
||||
```ignore
|
||||
# #![feature(old_io, std_misc)]
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
use std::sync::Mutex;
|
||||
|
||||
fn main() {
|
||||
@ -203,17 +161,17 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
timer::sleep(Duration::milliseconds(50));
|
||||
thread::sleep_ms(50);
|
||||
}
|
||||
```
|
||||
|
||||
Here's the error:
|
||||
|
||||
```text
|
||||
<anon>:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
|
||||
<anon>:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
|
||||
<anon>:11 thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
<anon>:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
|
||||
<anon>:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
|
||||
<anon>:11 thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
```
|
||||
@ -232,11 +190,8 @@ guard across thread boundaries, which gives us our error.
|
||||
We can use `Arc<T>` to fix this. Here's the working version:
|
||||
|
||||
```
|
||||
# #![feature(old_io, std_misc)]
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::old_io::timer;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
|
||||
@ -249,7 +204,7 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
timer::sleep(Duration::milliseconds(50));
|
||||
thread::sleep_ms(50);
|
||||
}
|
||||
```
|
||||
|
||||
@ -257,12 +212,9 @@ We now call `clone()` on our `Arc`, which increases the internal count. This
|
||||
handle is then moved into the new thread. Let's examine the body of the
|
||||
thread more closely:
|
||||
|
||||
```
|
||||
# #![feature(old_io, std_misc)]
|
||||
```rust
|
||||
# use std::sync::{Arc, Mutex};
|
||||
# use std::thread;
|
||||
# use std::old_io::timer;
|
||||
# use std::time::Duration;
|
||||
# fn main() {
|
||||
# let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
|
||||
# for i in 0..2 {
|
||||
@ -272,6 +224,7 @@ thread::spawn(move || {
|
||||
data[i] += 1;
|
||||
});
|
||||
# }
|
||||
# thread::sleep_ms(50);
|
||||
# }
|
||||
```
|
||||
|
||||
|
3
src/doc/trpl/conditional-compilation.md
Normal file
3
src/doc/trpl/conditional-compilation.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Conditional Compilation
|
||||
|
||||
Coming Soon!
|
3
src/doc/trpl/const.md
Normal file
3
src/doc/trpl/const.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `const`
|
||||
|
||||
Coming soon!
|
@ -111,8 +111,8 @@ Cargo will build this crate as a library:
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
$ ls target
|
||||
deps libphrases-a7448e02a0468eaa.rlib native
|
||||
$ ls target/debug
|
||||
build deps examples libphrases-a7448e02a0468eaa.rlib native
|
||||
```
|
||||
|
||||
`libphrase-hash.rlib` is the compiled crate. Before we see how to use this
|
||||
@ -163,9 +163,12 @@ $ tree .
|
||||
│ │ └── mod.rs
|
||||
│ └── lib.rs
|
||||
└── target
|
||||
├── deps
|
||||
├── libphrases-a7448e02a0468eaa.rlib
|
||||
└── native
|
||||
└── debug
|
||||
├── build
|
||||
├── deps
|
||||
├── examples
|
||||
├── libphrases-a7448e02a0468eaa.rlib
|
||||
└── native
|
||||
```
|
||||
|
||||
`src/lib.rs` is our crate root, and looks like this:
|
||||
@ -214,8 +217,6 @@ fn goodbye() -> String {
|
||||
Put this in `src/japanese/greetings.rs`:
|
||||
|
||||
```rust
|
||||
// in src/japanese/greetings.rs
|
||||
|
||||
fn hello() -> String {
|
||||
"こんにちは".to_string()
|
||||
}
|
||||
@ -275,14 +276,15 @@ this:
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
/home/you/projects/phrases/src/main.rs:4:38: 4:72 error: function `hello` is private
|
||||
/home/you/projects/phrases/src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello());
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/main.rs:4:38: 4:72 error: function `hello` is private
|
||||
src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello());
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
note: in expansion of format_args!
|
||||
<std macros>:2:23: 2:77 note: expansion site
|
||||
<std macros>:1:1: 3:2 note: in expansion of println!
|
||||
/home/you/projects/phrases/src/main.rs:4:5: 4:76 note: expansion site
|
||||
|
||||
<std macros>:2:25: 2:58 note: expansion site
|
||||
<std macros>:1:1: 2:62 note: in expansion of print!
|
||||
<std macros>:3:1: 3:54 note: expansion site
|
||||
<std macros>:1:1: 3:58 note: in expansion of println!
|
||||
phrases/src/main.rs:4:5: 4:76 note: expansion site
|
||||
```
|
||||
|
||||
By default, everything is private in Rust. Let's talk about this in some more
|
||||
@ -340,15 +342,15 @@ functions:
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1:1: 3:2 warning: code is never used: `hello`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1 fn hello() -> String {
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:2 "こんにちは".to_string()
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1:1: 3:2 warning: code is never used: `goodbye`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1 fn goodbye() -> String {
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:2 "さようなら".to_string()
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
|
||||
Running `target/phrases`
|
||||
src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default
|
||||
src/japanese/greetings.rs:1 fn hello() -> String {
|
||||
src/japanese/greetings.rs:2 "こんにちは".to_string()
|
||||
src/japanese/greetings.rs:3 }
|
||||
src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default
|
||||
src/japanese/farewells.rs:1 fn goodbye() -> String {
|
||||
src/japanese/farewells.rs:2 "さようなら".to_string()
|
||||
src/japanese/farewells.rs:3 }
|
||||
Running `target/debug/phrases`
|
||||
Hello in English: Hello!
|
||||
Goodbye in English: Goodbye.
|
||||
```
|
||||
@ -414,9 +416,9 @@ Rust will give us a compile-time error:
|
||||
|
||||
```text
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
/home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module
|
||||
/home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello;
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252]
|
||||
src/main.rs:4 use phrases::japanese::greetings::hello;
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
error: aborting due to previous error
|
||||
Could not compile `phrases`.
|
||||
```
|
||||
@ -523,7 +525,7 @@ This will build and run:
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
Running `target/phrases`
|
||||
Running `target/debug/phrases`
|
||||
Hello in English: Hello!
|
||||
Goodbye in English: Goodbye.
|
||||
Hello in Japanese: こんにちは
|
||||
|
3
src/doc/trpl/debug-and-display.md
Normal file
3
src/doc/trpl/debug-and-display.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Debug and Display
|
||||
|
||||
Coming soon!
|
3
src/doc/trpl/deref-coercions.md
Normal file
3
src/doc/trpl/deref-coercions.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `Deref` coercions
|
||||
|
||||
Coming soon!
|
3
src/doc/trpl/drop.md
Normal file
3
src/doc/trpl/drop.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `Drop`
|
||||
|
||||
Coming soon!
|
8
src/doc/trpl/effective-rust.md
Normal file
8
src/doc/trpl/effective-rust.md
Normal file
@ -0,0 +1,8 @@
|
||||
% Effective Rust
|
||||
|
||||
So you’ve learned how to write some Rust code. But there’s a difference between
|
||||
writing *any* Rust code and writing *good* Rust code.
|
||||
|
||||
This section consists of relatively independent tutorials which show you how to
|
||||
take your Rust to the next level. Common patterns and standard library features
|
||||
will be introduced. Read these sections in any order of your choosing.
|
147
src/doc/trpl/enums.md
Normal file
147
src/doc/trpl/enums.md
Normal file
@ -0,0 +1,147 @@
|
||||
% Enums
|
||||
|
||||
Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful
|
||||
feature of Rust, and are used throughout the standard library. An `enum` is
|
||||
a type which relates a set of alternates to a specific name. For example, below
|
||||
we define `Character` to be either a `Digit` or something else. These
|
||||
can be used via their fully scoped names: `Character::Other` (more about `::`
|
||||
below).
|
||||
|
||||
```rust
|
||||
enum Character {
|
||||
Digit(i32),
|
||||
Other,
|
||||
}
|
||||
```
|
||||
|
||||
Most normal types are allowed as the variant components of an `enum`. Here are
|
||||
some examples:
|
||||
|
||||
```rust
|
||||
struct Empty;
|
||||
struct Color(i32, i32, i32);
|
||||
struct Length(i32);
|
||||
struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
|
||||
struct HeightDatabase(Vec<i32>);
|
||||
```
|
||||
|
||||
You see that, depending on its type, an `enum` variant may or may not hold data.
|
||||
In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
|
||||
value, where `Other` is only a name. However, the fact that they represent
|
||||
distinct categories of `Character` is a very useful property.
|
||||
|
||||
As with structures, the variants of an enum by default are not comparable with
|
||||
equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not
|
||||
support other binary operations such as `*` and `+`. As such, the following code
|
||||
is invalid for the example `Character` type:
|
||||
|
||||
```{rust,ignore}
|
||||
// These assignments both succeed
|
||||
let ten = Character::Digit(10);
|
||||
let four = Character::Digit(4);
|
||||
|
||||
// Error: `*` is not implemented for type `Character`
|
||||
let forty = ten * four;
|
||||
|
||||
// Error: `<=` is not implemented for type `Character`
|
||||
let four_is_smaller = four <= ten;
|
||||
|
||||
// Error: `==` is not implemented for type `Character`
|
||||
let four_equals_ten = four == ten;
|
||||
```
|
||||
|
||||
This may seem rather limiting, but it's a limitation which we can overcome.
|
||||
There are two ways: by implementing equality ourselves, or by pattern matching
|
||||
variants with [`match`][match] expressions, which you'll learn in the next
|
||||
chapter. We don't know enough about Rust to implement equality yet, but we can
|
||||
use the `Ordering` enum from the standard library, which does:
|
||||
|
||||
```
|
||||
enum Ordering {
|
||||
Less,
|
||||
Equal,
|
||||
Greater,
|
||||
}
|
||||
```
|
||||
|
||||
Because `Ordering` has already been defined for us, we will import it with the
|
||||
`use` keyword. Here's an example of how it is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives
|
||||
in the `cmp` submodule of the `std` module. We'll talk more about modules later
|
||||
in the guide. For now, all you need to know is that you can `use` things from
|
||||
the standard library if you need them.
|
||||
|
||||
Okay, let's talk about the actual code in the example. `cmp` is a function that
|
||||
compares two things, and returns an `Ordering`. We return either
|
||||
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
|
||||
whether the first value is less than, greater than, or equal to the second. Note
|
||||
that each variant of the `enum` is namespaced under the `enum` itself: it's
|
||||
`Ordering::Greater`, not `Greater`.
|
||||
|
||||
The `ordering` variable has the type `Ordering`, and so contains one of the
|
||||
three values. We then do a bunch of `if`/`else` comparisons to check which
|
||||
one it is.
|
||||
|
||||
This `Ordering::Greater` notation is too long. Let's use another form of `use`
|
||||
to import the `enum` variants instead. This will avoid full scoping:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering::{self, Equal, Less, Greater};
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Less }
|
||||
else if a > b { Greater }
|
||||
else { Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Less { println!("less"); }
|
||||
else if ordering == Greater { println!("greater"); }
|
||||
else if ordering == Equal { println!("equal"); }
|
||||
}
|
||||
```
|
||||
|
||||
Importing variants is convenient and compact, but can also cause name conflicts,
|
||||
so do this with caution. For this reason, it's normally considered better style
|
||||
to `use` an enum rather than its variants directly.
|
||||
|
||||
As you can see, `enum`s are quite a powerful tool for data representation, and
|
||||
are even more useful when they're [generic][generics] across types. Before we
|
||||
get to generics, though, let's talk about how to use enums with pattern
|
||||
matching, a tool that will let us deconstruct sum types (the type theory term
|
||||
for enums) like `Ordering` in a very elegant way that avoids all these messy
|
||||
and brittle `if`/`else`s.
|
||||
|
||||
[match]: ./match.html
|
||||
[generics]: ./generics.html
|
@ -297,5 +297,5 @@ It's worth noting that you can only use `try!` from a function that returns a
|
||||
`Result`, which means that you cannot use `try!` inside of `main()`, because
|
||||
`main()` doesn't return anything.
|
||||
|
||||
`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine
|
||||
`try!` makes use of [`From<Error>`](../std/convert/trait.From.hml) to determine
|
||||
what to return in the error case.
|
||||
|
@ -166,7 +166,7 @@ pub fn uncompress(src: &[u8]) -> Option<Vec<u8>> {
|
||||
}
|
||||
```
|
||||
|
||||
For reference, the examples used here are also available as an [library on
|
||||
For reference, the examples used here are also available as a [library on
|
||||
GitHub](https://github.com/thestinger/rust-snappy).
|
||||
|
||||
# Destructors
|
||||
|
43
src/doc/trpl/for-loops.md
Normal file
43
src/doc/trpl/for-loops.md
Normal file
@ -0,0 +1,43 @@
|
||||
% for Loops
|
||||
|
||||
The `for` loop is used to loop a particular number of times. Rust’s `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust’s `for`
|
||||
loop doesn’t look like this “C-style” `for` loop:
|
||||
|
||||
```c
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
Instead, it looks like this:
|
||||
|
||||
```rust
|
||||
for x in 0..10 {
|
||||
println!("{}", x); // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```ignore
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an [iterator][iterator]. The iterator gives back a series of
|
||||
elements. Each element is one iteration of the loop. That value is then bound
|
||||
to the name `var`, which is valid for the loop body. Once the body is over, the
|
||||
next value is fetched from the iterator, and we loop another time. When there
|
||||
are no more values, the `for` loop is over.
|
||||
|
||||
[iterator]: iterators.html
|
||||
|
||||
In our example, `0..10` is an expression that takes a start and an end position,
|
||||
and gives an iterator over those values. The upper bound is exclusive, though,
|
||||
so our loop will print `0` through `9`, not `10`.
|
||||
|
||||
Rust does not have the “C-style” `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers.
|
@ -1,6 +1,6 @@
|
||||
% Functions
|
||||
|
||||
You've already seen one function so far, the `main` function:
|
||||
Every Rust program has at least one function, the `main` function:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -8,16 +8,16 @@ fn main() {
|
||||
```
|
||||
|
||||
This is the simplest possible function declaration. As we mentioned before,
|
||||
`fn` says "this is a function," followed by the name, some parentheses because
|
||||
`fn` says ‘this is a function’, followed by the name, some parentheses because
|
||||
this function takes no arguments, and then some curly braces to indicate the
|
||||
body. Here's a function named `foo`:
|
||||
body. Here’s a function named `foo`:
|
||||
|
||||
```rust
|
||||
fn foo() {
|
||||
}
|
||||
```
|
||||
|
||||
So, what about taking arguments? Here's a function that prints a number:
|
||||
So, what about taking arguments? Here’s a function that prints a number:
|
||||
|
||||
```rust
|
||||
fn print_number(x: i32) {
|
||||
@ -25,7 +25,7 @@ fn print_number(x: i32) {
|
||||
}
|
||||
```
|
||||
|
||||
Here's a complete program that uses `print_number`:
|
||||
Here’s a complete program that uses `print_number`:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -40,7 +40,7 @@ fn print_number(x: i32) {
|
||||
As you can see, function arguments work very similar to `let` declarations:
|
||||
you add a type to the argument name, after a colon.
|
||||
|
||||
Here's a complete program that adds two numbers together and prints them:
|
||||
Here’s a complete program that adds two numbers together and prints them:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -58,7 +58,7 @@ as when you declare it.
|
||||
Unlike `let`, you _must_ declare the types of function arguments. This does
|
||||
not work:
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
fn print_sum(x, y) {
|
||||
println!("sum is: {}", x + y);
|
||||
}
|
||||
@ -67,8 +67,8 @@ fn print_sum(x, y) {
|
||||
You get this error:
|
||||
|
||||
```text
|
||||
hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)`
|
||||
hello.rs:5 fn print_number(x, y) {
|
||||
expected one of `!`, `:`, or `@`, found `)`
|
||||
fn print_number(x, y) {
|
||||
```
|
||||
|
||||
This is a deliberate design decision. While full-program inference is possible,
|
||||
@ -77,7 +77,7 @@ types explicitly is a best-practice. We agree that forcing functions to declare
|
||||
types while allowing for inference inside of function bodies is a wonderful
|
||||
sweet spot between full inference and no inference.
|
||||
|
||||
What about returning a value? Here's a function that adds one to an integer:
|
||||
What about returning a value? Here’s a function that adds one to an integer:
|
||||
|
||||
```rust
|
||||
fn add_one(x: i32) -> i32 {
|
||||
@ -86,11 +86,11 @@ fn add_one(x: i32) -> i32 {
|
||||
```
|
||||
|
||||
Rust functions return exactly one value, and you declare the type after an
|
||||
"arrow," which is a dash (`-`) followed by a greater-than sign (`>`).
|
||||
‘arrow’, which is a dash (`-`) followed by a greater-than sign (`>`). The last
|
||||
line of a function determines what it returns. You’ll note the lack of a
|
||||
semicolon here. If we added it in:
|
||||
|
||||
You'll note the lack of a semicolon here. If we added it in:
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1;
|
||||
}
|
||||
@ -109,24 +109,79 @@ help: consider removing this semicolon:
|
||||
^
|
||||
```
|
||||
|
||||
Remember our earlier discussions about semicolons and `()`? Our function claims
|
||||
to return an `i32`, but with a semicolon, it would return `()` instead. Rust
|
||||
realizes this probably isn't what we want, and suggests removing the semicolon.
|
||||
This reveals two interesting things about Rust: it is an expression-based
|
||||
language, and semicolons are different from semicolons in other ‘curly brace
|
||||
and semicolon’-based languages. These two things are related.
|
||||
|
||||
This is very much like our `if` statement before: the result of the block
|
||||
(`{}`) is the value of the expression. Other expression-oriented languages,
|
||||
such as Ruby, work like this, but it's a bit unusual in the systems programming
|
||||
world. When people first learn about this, they usually assume that it
|
||||
introduces bugs. But because Rust's type system is so strong, and because unit
|
||||
is its own unique type, we have never seen an issue where adding or removing a
|
||||
semicolon in a return position would cause a bug.
|
||||
## Expressions vs. Statements
|
||||
|
||||
Rust is primarily an expression-based language. There are only two kinds of
|
||||
statements, and everything else is an expression.
|
||||
|
||||
So what's the difference? Expressions return a value, and statements do not.
|
||||
That’s why we end up with ‘not all control paths return a value’ here: the
|
||||
statement `x + 1;` doesn’t return a value. There are two kinds of statements in
|
||||
Rust: ‘declaration statements’ and ‘expression statements’. Everything else is
|
||||
an expression. Let’s talk about declaration statements first.
|
||||
|
||||
In some languages, variable bindings can be written as expressions, not just
|
||||
statements. Like Ruby:
|
||||
|
||||
```ruby
|
||||
x = y = 5
|
||||
```
|
||||
|
||||
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||
following will produce a compile-time error:
|
||||
|
||||
```ignore
|
||||
let x = (let y = 5); // expected identifier, found keyword `let`
|
||||
```
|
||||
|
||||
The compiler is telling us here that it was expecting to see the beginning of
|
||||
an expression, and a `let` can only begin a statement, not an expression.
|
||||
|
||||
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
|
||||
expression, although its value is not particularly useful. Unlike other
|
||||
languages where an assignment evaluates to the assigned value (e.g. `5` in the
|
||||
previous example), in Rust the value of an assignment is an empty tuple `()`:
|
||||
|
||||
```
|
||||
let mut y = 5;
|
||||
|
||||
let x = (y = 6); // x has the value `()`, not `6`
|
||||
```
|
||||
|
||||
The second kind of statement in Rust is the *expression statement*. Its
|
||||
purpose is to turn any expression into a statement. In practical terms, Rust's
|
||||
grammar expects statements to follow other statements. This means that you use
|
||||
semicolons to separate expressions from each other. This means that Rust
|
||||
looks a lot like most other languages that require you to use semicolons
|
||||
at the end of every line, and you will see semicolons at the end of almost
|
||||
every line of Rust code you see.
|
||||
|
||||
What is this exception that makes us say "almost"? You saw it already, in this
|
||||
code:
|
||||
|
||||
```rust
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Our function claims to return an `i32`, but with a semicolon, it would return
|
||||
`()` instead. Rust realizes this probably isn’t what we want, and suggests
|
||||
removing the semicolon in the error we saw before.
|
||||
|
||||
## Early returns
|
||||
|
||||
But what about early returns? Rust does have a keyword for that, `return`:
|
||||
|
||||
```rust
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 { return x; }
|
||||
return x;
|
||||
|
||||
// we never run this code!
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
@ -136,33 +191,17 @@ style:
|
||||
|
||||
```rust
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 { return x; }
|
||||
|
||||
return x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
The previous definition without `return` may look a bit strange if you haven't
|
||||
The previous definition without `return` may look a bit strange if you haven’t
|
||||
worked in an expression-based language before, but it becomes intuitive over
|
||||
time. If this were production code, we wouldn't write it in that way anyway,
|
||||
we'd write this:
|
||||
|
||||
```rust
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 {
|
||||
x
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Because `if` is an expression, and it's the only expression in this function,
|
||||
the value will be the result of the `if`.
|
||||
time.
|
||||
|
||||
## Diverging functions
|
||||
|
||||
Rust has some special syntax for 'diverging functions', which are functions that
|
||||
Rust has some special syntax for ‘diverging functions’, which are functions that
|
||||
do not return:
|
||||
|
||||
```
|
||||
@ -171,23 +210,18 @@ fn diverges() -> ! {
|
||||
}
|
||||
```
|
||||
|
||||
`panic!` is a macro, similar to `println!()` that we've already seen. Unlike
|
||||
`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike
|
||||
`println!()`, `panic!()` causes the current thread of execution to crash with
|
||||
the given message.
|
||||
|
||||
Because this function will cause a crash, it will never return, and so it has
|
||||
the type '`!`', which is read "diverges." A diverging function can be used
|
||||
the type ‘`!`’, which is read ‘diverges’. A diverging function can be used
|
||||
as any type:
|
||||
|
||||
```should_panic
|
||||
# fn diverges() -> ! {
|
||||
# panic!("This function never returns!");
|
||||
# }
|
||||
|
||||
let x: i32 = diverges();
|
||||
let x: String = diverges();
|
||||
```
|
||||
|
||||
We don't have a good use for diverging functions yet, because they're used in
|
||||
conjunction with other Rust features. But when you see `-> !` later, you'll
|
||||
know what it's called.
|
||||
|
5
src/doc/trpl/getting-started.md
Normal file
5
src/doc/trpl/getting-started.md
Normal file
@ -0,0 +1,5 @@
|
||||
% Getting Started
|
||||
|
||||
This first section of the book will get you going with Rust and its tooling.
|
||||
First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally,
|
||||
we’ll talk about Cargo, Rust’s build system and package manager.
|
@ -1,26 +1,27 @@
|
||||
% Hello, Cargo!
|
||||
|
||||
[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their
|
||||
Rust projects. Cargo is currently in an alpha state, just like Rust, and so it
|
||||
is still a work in progress. However, it is already good enough to use for many
|
||||
Rust projects, and so it is assumed that Rust projects will use Cargo from the
|
||||
beginning.
|
||||
[Cargo][cratesio] is a tool that Rustaceans use to help manage their Rust
|
||||
projects. Cargo is currently in a pre-1.0 state, and so it is still a work in
|
||||
progress. However, it is already good enough to use for many Rust projects, and
|
||||
so it is assumed that Rust projects will use Cargo from the beginning.
|
||||
|
||||
[cratesio]: https://doc.crates.io
|
||||
|
||||
Cargo manages three things: building your code, downloading the dependencies
|
||||
your code needs, and building those dependencies. At first, your
|
||||
program doesn't have any dependencies, so we'll only be using the first part of
|
||||
its functionality. Eventually, we'll add more. Since we started off by using
|
||||
program doesn’t have any dependencies, so we’ll only be using the first part of
|
||||
its functionality. Eventually, we’ll add more. Since we started off by using
|
||||
Cargo, it'll be easy to add later.
|
||||
|
||||
If you installed Rust via the official installers you will also have
|
||||
Cargo. If you installed Rust some other way, you may want to [check
|
||||
the Cargo
|
||||
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
|
||||
for specific instructions about installing it.
|
||||
If you installed Rust via the official installers you will also have Cargo. If
|
||||
you installed Rust some other way, you may want to [check the Cargo
|
||||
README][cargoreadme] for specific instructions about installing it.
|
||||
|
||||
[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies
|
||||
|
||||
## Converting to Cargo
|
||||
|
||||
Let's convert Hello World to Cargo.
|
||||
Let’s convert Hello World to Cargo.
|
||||
|
||||
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
|
||||
configuration file, and put our source file in the right place. Let's
|
||||
@ -52,14 +53,9 @@ Put this inside:
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
authors = [ "Your name <you@example.com>" ]
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "hello_world"
|
||||
```
|
||||
|
||||
This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let
|
||||
it explain itself to you:
|
||||
This file is in the [TOML][toml] format. Let’s let it explain itself to you:
|
||||
|
||||
> TOML aims to be a minimal configuration file format that's easy to read due
|
||||
> to obvious semantics. TOML is designed to map unambiguously to a hash table.
|
||||
@ -68,10 +64,7 @@ it explain itself to you:
|
||||
|
||||
TOML is very similar to INI, but with some extra goodies.
|
||||
|
||||
Anyway, there are two *tables* in this file: `package` and `bin`. The first
|
||||
tells Cargo metadata about your package. The second tells Cargo that we're
|
||||
interested in building a binary, not a library (though we could do both!), as
|
||||
well as what it is named.
|
||||
[toml]: https://github.com/toml-lang/toml
|
||||
|
||||
Once you have this file in place, we should be ready to build! Try this:
|
||||
|
||||
@ -83,13 +76,32 @@ Hello, world!
|
||||
```
|
||||
|
||||
Bam! We build our project with `cargo build`, and run it with
|
||||
`./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use
|
||||
of `rustc`, but think about the future: when our project has more than one
|
||||
file, we would need to call `rustc` more than once and pass it a bunch of options to
|
||||
tell it to build everything together. With Cargo, as our project grows, we can
|
||||
just `cargo build`, and it'll work the right way. When your project is finally
|
||||
ready for release, you can use `cargo build --release` to compile your crates with
|
||||
optimizations.
|
||||
`./target/debug/hello_world`. We can do both in one step with `cargo run`:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Running `target/debug/hello_world`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Notice that we didn’t re-build the project this time. Cargo figured out that
|
||||
we hadn’t changed the source file, and so it just ran the binary. If we had
|
||||
made a modification, we would have seen it do both:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
|
||||
Running `target/debug/hello_world`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
This hasn’t bought us a whole lot over our simple use of `rustc`, but think
|
||||
about the future: when our project gets more complex, we would need to do more
|
||||
things to get all of the parts to properly compile. With Cargo, as our project
|
||||
grows, we can just `cargo build`, and it’ll work the right way.
|
||||
|
||||
When your project is finally ready for release, you can use
|
||||
`cargo build --release` to compile your project with optimizations.
|
||||
|
||||
You'll also notice that Cargo has created a new file: `Cargo.lock`.
|
||||
|
||||
@ -100,18 +112,25 @@ version = "0.0.1"
|
||||
```
|
||||
|
||||
This file is used by Cargo to keep track of dependencies in your application.
|
||||
Right now, we don't have any, so it's a bit sparse. You won't ever need
|
||||
Right now, we don’t have any, so it’s a bit sparse. You won't ever need
|
||||
to touch this file yourself, just let Cargo handle it.
|
||||
|
||||
That's it! We've successfully built `hello_world` with Cargo. Even though our
|
||||
program is simple, it's using much of the real tooling that you'll use for the
|
||||
rest of your Rust career.
|
||||
That’s it! We’ve successfully built `hello_world` with Cargo. Even though our
|
||||
program is simple, it’s using much of the real tooling that you’ll use for the
|
||||
rest of your Rust career. You can expect to do this to get started with
|
||||
virtually all Rust projects:
|
||||
|
||||
```bash
|
||||
$ git clone someurl.com/foo
|
||||
$ cd foo
|
||||
$ cargo build
|
||||
```
|
||||
|
||||
## A New Project
|
||||
|
||||
You don't have to go through this whole process every time you want to start a new
|
||||
project! Cargo has the ability to make a bare-bones project directory in which you
|
||||
can start developing right away.
|
||||
You don’t have to go through this whole process every time you want to start a
|
||||
new project! Cargo has the ability to make a bare-bones project directory in
|
||||
which you can start developing right away.
|
||||
|
||||
To start a new project with Cargo, use `cargo new`:
|
||||
|
||||
@ -119,8 +138,8 @@ To start a new project with Cargo, use `cargo new`:
|
||||
$ cargo new hello_world --bin
|
||||
```
|
||||
|
||||
We're passing `--bin` because we're making a binary program: if we
|
||||
were making a library, we'd leave it off.
|
||||
We’re passing `--bin` because we're making a binary program: if we were making
|
||||
a library, we'd leave it off.
|
||||
|
||||
Let's check out what Cargo has generated for us:
|
||||
|
||||
@ -135,10 +154,10 @@ $ tree .
|
||||
1 directory, 2 files
|
||||
```
|
||||
|
||||
If you don't have the `tree` command, you can probably get it from your distro's package
|
||||
manager. It's not necessary, but it's certainly useful.
|
||||
If you don't have the `tree` command, you can probably get it from your
|
||||
distribution’s package manager. It’s not necessary, but it’s certainly useful.
|
||||
|
||||
This is all we need to get started. First, let's check out `Cargo.toml`:
|
||||
This is all we need to get started. First, let’s check out `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
@ -148,11 +167,11 @@ version = "0.0.1"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
Cargo has populated this file with reasonable defaults based off the arguments you gave
|
||||
it and your `git` global configuration. You may notice that Cargo has also initialized
|
||||
the `hello_world` directory as a `git` repository.
|
||||
Cargo has populated this file with reasonable defaults based off the arguments
|
||||
you gave it and your `git` global configuration. You may notice that Cargo has
|
||||
also initialized the `hello_world` directory as a `git` repository.
|
||||
|
||||
Here's what's in `src/main.rs`:
|
||||
Here’s what’s in `src/main.rs`:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -160,9 +179,20 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Cargo has generated a "Hello World!" for us, and you're ready to start coding! A
|
||||
much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html).
|
||||
Cargo has generated a "Hello World!" for us, and you’re ready to start coding! Cargo
|
||||
has its own [guide][guide] which covers Cargo’s features in much more depth.
|
||||
|
||||
Now that you've got the tools down, let's actually learn more about the Rust
|
||||
[guide]: http://doc.crates.io/guide.html
|
||||
|
||||
Now that you’ve got the tools down, let’s actually learn more about the Rust
|
||||
language itself. These are the basics that will serve you well through the rest
|
||||
of your time with Rust.
|
||||
|
||||
You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or
|
||||
start from the bottom and work your way up with ‘[Syntax and
|
||||
Semantics][syntax]’. More experienced systems programmers will probably prefer
|
||||
‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different
|
||||
people learn differently! Choose whatever’s right for you.
|
||||
|
||||
[learnrust]: learn-rust.html
|
||||
[syntax]: syntax-and-semantics.html
|
||||
|
@ -1,9 +1,9 @@
|
||||
% Hello, world!
|
||||
|
||||
Now that you have Rust installed, let's write your first Rust program. It's
|
||||
Now that you have Rust installed, let’s write your first Rust program. It’s
|
||||
traditional to make your first program in any new language one that prints the
|
||||
text "Hello, world!" to the screen. The nice thing about starting with such a
|
||||
simple program is that you can verify that your compiler isn't just installed,
|
||||
text “Hello, world!” to the screen. The nice thing about starting with such a
|
||||
simple program is that you can verify that your compiler isn’t just installed,
|
||||
but also working properly. And printing information to the screen is a pretty
|
||||
common thing to do.
|
||||
|
||||
@ -12,38 +12,37 @@ to make a `projects` directory in my home directory, and keep all my projects
|
||||
there. Rust does not care where your code lives.
|
||||
|
||||
This actually leads to one other concern we should address: this guide will
|
||||
assume that you have basic familiarity with the command line. Rust does not
|
||||
require that you know a whole ton about the command line, but until the
|
||||
language is in a more finished state, IDE support is spotty. Rust makes no
|
||||
specific demands on your editing tooling, or where your code lives.
|
||||
assume that you have basic familiarity with the command line. Rust itself makes
|
||||
no specific demands on your editing tooling, or where your code lives. If you
|
||||
prefer an IDE to the command line, you may want to check out
|
||||
[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are
|
||||
a number of extensions of varying quality in development by the community. The
|
||||
Rust team also ships [plugins for various editors][plugins]. Configuring your
|
||||
editor or IDE is out of the scope of this tutorial, so check the documentation
|
||||
for your setup, specifically.
|
||||
|
||||
With that said, let's make a directory in our projects directory.
|
||||
[solidoak]: https://github.com/oakes/SolidOak
|
||||
[plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md
|
||||
|
||||
```{bash}
|
||||
With that said, let’s make a directory in our projects directory.
|
||||
|
||||
```bash
|
||||
$ mkdir ~/projects
|
||||
$ cd ~/projects
|
||||
$ mkdir hello_world
|
||||
$ cd hello_world
|
||||
```
|
||||
|
||||
If you're on Windows and not using PowerShell, the `~` may not work. Consult
|
||||
If you’re on Windows and not using PowerShell, the `~` may not work. Consult
|
||||
the documentation for your shell for more details.
|
||||
|
||||
Let's make a new source file next. I'm going to use the syntax `editor
|
||||
filename` to represent editing a file in these examples, but you should use
|
||||
whatever method you want. We'll call our file `main.rs`:
|
||||
Let’s make a new source file next. We’ll call our file `main.rs`. Rust files
|
||||
always end in a `.rs` extension. If you’re using more than one word in your
|
||||
filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`.
|
||||
|
||||
```{bash}
|
||||
$ editor main.rs
|
||||
```
|
||||
Now that you’ve got your file open, type this in:
|
||||
|
||||
Rust files always end in a `.rs` extension. If you're using more than one word
|
||||
in your filename, use an underscore. `hello_world.rs` rather than
|
||||
`helloworld.rs`.
|
||||
|
||||
Now that you've got your file open, type this in:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
@ -51,87 +50,90 @@ fn main() {
|
||||
|
||||
Save the file, and then type this into your terminal window:
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ rustc main.rs
|
||||
$ ./main # or main.exe on Windows
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code.
|
||||
Success! Let’s go over what just happened in detail.
|
||||
|
||||
Success! Let's go over what just happened in detail.
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
These lines define a *function* in Rust. The `main` function is special:
|
||||
it's the beginning of every Rust program. The first line says "I'm declaring a
|
||||
function named `main`, which takes no arguments and returns nothing." If there
|
||||
it's the beginning of every Rust program. The first line says "I’m declaring a
|
||||
function named `main` which takes no arguments and returns nothing." If there
|
||||
were arguments, they would go inside the parentheses (`(` and `)`), and because
|
||||
we aren't returning anything from this function, we can omit the return type
|
||||
entirely. We'll get to it later.
|
||||
we aren’t returning anything from this function, we can omit the return type
|
||||
entirely. We’ll get to it later.
|
||||
|
||||
You'll also note that the function is wrapped in curly braces (`{` and `}`).
|
||||
You’ll also note that the function is wrapped in curly braces (`{` and `}`).
|
||||
Rust requires these around all function bodies. It is also considered good
|
||||
style to put the opening curly brace on the same line as the function
|
||||
declaration, with one space in between.
|
||||
|
||||
Next up is this line:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
println!("Hello, world!");
|
||||
```
|
||||
|
||||
This line does all of the work in our little program. There are a number of
|
||||
details that are important here. The first is that it's indented with four
|
||||
details that are important here. The first is that it’s indented with four
|
||||
spaces, not tabs. Please configure your editor of choice to insert four spaces
|
||||
with the tab key. We provide some [sample configurations for various
|
||||
editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md).
|
||||
editors][configs].
|
||||
|
||||
The second point is the `println!()` part. This is calling a Rust *macro*,
|
||||
[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md
|
||||
|
||||
The second point is the `println!()` part. This is calling a Rust [macro][macro],
|
||||
which is how metaprogramming is done in Rust. If it were a function instead, it
|
||||
would look like this: `println()`. For our purposes, we don't need to worry
|
||||
about this difference. Just know that sometimes, you'll see a `!`, and that
|
||||
means that you're calling a macro instead of a normal function. Rust implements
|
||||
`println!` as a macro rather than a function for good reasons, but that's a
|
||||
very advanced topic. You'll learn more when we talk about macros later. One
|
||||
last thing to mention: Rust's macros are significantly different from C macros,
|
||||
if you've used those. Don't be scared of using macros. We'll get to the details
|
||||
eventually, you'll just have to trust us for now.
|
||||
would look like this: `println()`. For our purposes, we don’t need to worry
|
||||
about this difference. Just know that sometimes, you’ll see a `!`, and that
|
||||
means that you’re calling a macro instead of a normal function. Rust implements
|
||||
`println!` as a macro rather than a function for good reasons, but that's an
|
||||
advanced topic. One last thing to mention: Rust’s macros are significantly
|
||||
different from C macros, if you’ve used those. Don’t be scared of using macros.
|
||||
We’ll get to the details eventually, you’ll just have to trust us for now.
|
||||
|
||||
Next, `"Hello, world!"` is a *string*. Strings are a surprisingly complicated
|
||||
topic in a systems programming language, and this is a *statically allocated*
|
||||
string. We will talk more about different kinds of allocation later. We pass
|
||||
this string as an argument to `println!`, which prints the string to the
|
||||
screen. Easy enough!
|
||||
[macro]: macros.html
|
||||
|
||||
Finally, the line ends with a semicolon (`;`). Rust is an *expression
|
||||
oriented* language, which means that most things are expressions. The `;` is
|
||||
used to indicate that this expression is over, and the next one is ready to
|
||||
begin. Most lines of Rust code end with a `;`. We will cover this in-depth
|
||||
later in the guide.
|
||||
Next, `"Hello, world!"` is a ‘string’. Strings are a surprisingly complicated
|
||||
topic in a systems programming language, and this is a ‘statically allocated’
|
||||
string. If you want to read further about allocation, check out
|
||||
[the stack and the heap][allocation], but you don’t need to right now if you
|
||||
don’t want to. We pass this string as an argument to `println!`, which prints the
|
||||
string to the screen. Easy enough!
|
||||
|
||||
Finally, actually *compiling* and *running* our program. We can compile
|
||||
with our compiler, `rustc`, by passing it the name of our source file:
|
||||
[allocation]: the-stack-and-the-heap.html
|
||||
|
||||
```{bash}
|
||||
Finally, the line ends with a semicolon (`;`). Rust is an ‘expression oriented’
|
||||
language, which means that most things are expressions, rather than statements.
|
||||
The `;` is used to indicate that this expression is over, and the next one is
|
||||
ready to begin. Most lines of Rust code end with a `;`.
|
||||
|
||||
Finally, actually compiling and running our program. We can compile with our
|
||||
compiler, `rustc`, by passing it the name of our source file:
|
||||
|
||||
```bash
|
||||
$ rustc main.rs
|
||||
```
|
||||
|
||||
This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust
|
||||
will output a binary executable. You can see it with `ls`:
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ ls
|
||||
main main.rs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ dir
|
||||
main.exe main.rs
|
||||
```
|
||||
@ -139,7 +141,7 @@ main.exe main.rs
|
||||
There are now two files: our source code, with the `.rs` extension, and the
|
||||
executable (`main.exe` on Windows, `main` everywhere else)
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ ./main # or main.exe on Windows
|
||||
```
|
||||
|
||||
@ -147,15 +149,15 @@ This prints out our `Hello, world!` text to our terminal.
|
||||
|
||||
If you come from a dynamically typed language like Ruby, Python, or JavaScript,
|
||||
you may not be used to these two steps being separate. Rust is an
|
||||
*ahead-of-time compiled language*, which means that you can compile a
|
||||
program, give it to someone else, and they don't need to have Rust installed.
|
||||
If you give someone a `.rb` or `.py` or `.js` file, they need to have
|
||||
Ruby/Python/JavaScript installed, but you just need one command to both compile
|
||||
and run your program. Everything is a tradeoff in language design, and Rust has
|
||||
made its choice.
|
||||
‘ahead-of-time compiled language’, which means that you can compile a program,
|
||||
give it to someone else, and they don't need to have Rust installed. If you
|
||||
give someone a `.rb` or `.py` or `.js` file, they need to have a
|
||||
Ruby/Python/JavaScript implementation installed, but you just need one command
|
||||
to both compile and run your program. Everything is a tradeoff in language
|
||||
design, and Rust has made its choice.
|
||||
|
||||
Congratulations! You have officially written a Rust program. That makes you a
|
||||
Rust programmer! Welcome.
|
||||
Rust programmer! Welcome. 🎊🎉👍
|
||||
|
||||
Next, I'd like to introduce you to another tool, Cargo, which is used to write
|
||||
real-world Rust programs. Just using `rustc` is nice for simple things, but as
|
||||
|
3
src/doc/trpl/if-let.md
Normal file
3
src/doc/trpl/if-let.md
Normal file
@ -0,0 +1,3 @@
|
||||
% if let
|
||||
|
||||
COMING SOON
|
@ -1,10 +1,10 @@
|
||||
% If
|
||||
% if
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
||||
systems language. So let's talk about it, to make sure you grasp the nuances.
|
||||
Rust’s take on `if` is not particularly complex, but it’s much more like the
|
||||
`if` you’ll find in a dynamically typed language than in a more traditional
|
||||
systems language. So let’s talk about it, to make sure you grasp the nuances.
|
||||
|
||||
`if` is a specific form of a more general concept, the *branch*. The name comes
|
||||
`if` is a specific form of a more general concept, the ‘branch’. The name comes
|
||||
from a branch in a tree: a decision point, where depending on a choice,
|
||||
multiple paths can be taken.
|
||||
|
||||
@ -20,11 +20,11 @@ if x == 5 {
|
||||
|
||||
If we changed the value of `x` to something else, this line would not print.
|
||||
More specifically, if the expression after the `if` evaluates to `true`, then
|
||||
the block is executed. If it's `false`, then it is not.
|
||||
the block is executed. If it’s `false`, then it is not.
|
||||
|
||||
If you want something to happen in the `false` case, use an `else`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
if x == 5 {
|
||||
@ -50,8 +50,7 @@ if x == 5 {
|
||||
|
||||
This is all pretty standard. However, you can also do this:
|
||||
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
let y = if x == 5 {
|
||||
@ -63,93 +62,12 @@ let y = if x == 5 {
|
||||
|
||||
Which we can (and probably should) write like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
let y = if x == 5 { 10 } else { 15 }; // y: i32
|
||||
```
|
||||
|
||||
This reveals two interesting things about Rust: it is an expression-based
|
||||
language, and semicolons are different from semicolons in other 'curly brace
|
||||
and semicolon'-based languages. These two things are related.
|
||||
|
||||
## Expressions vs. Statements
|
||||
|
||||
Rust is primarily an expression based language. There are only two kinds of
|
||||
statements, and everything else is an expression.
|
||||
|
||||
So what's the difference? Expressions return a value, and statements do not.
|
||||
In many languages, `if` is a statement, and therefore, `let x = if ...` would
|
||||
make no sense. But in Rust, `if` is an expression, which means that it returns
|
||||
a value. We can then use this value to initialize the binding.
|
||||
|
||||
Speaking of which, bindings are a kind of the first of Rust's two statements.
|
||||
The proper name is a *declaration statement*. So far, `let` is the only kind
|
||||
of declaration statement we've seen. Let's talk about that some more.
|
||||
|
||||
In some languages, variable bindings can be written as expressions, not just
|
||||
statements. Like Ruby:
|
||||
|
||||
```{ruby}
|
||||
x = y = 5
|
||||
```
|
||||
|
||||
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||
following will produce a compile-time error:
|
||||
|
||||
```{ignore}
|
||||
let x = (let y = 5); // expected identifier, found keyword `let`
|
||||
```
|
||||
|
||||
The compiler is telling us here that it was expecting to see the beginning of
|
||||
an expression, and a `let` can only begin a statement, not an expression.
|
||||
|
||||
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
|
||||
expression, although its value is not particularly useful. Unlike C, where an
|
||||
assignment evaluates to the assigned value (e.g. `5` in the previous example),
|
||||
in Rust the value of an assignment is the unit type `()` (which we'll cover later).
|
||||
|
||||
The second kind of statement in Rust is the *expression statement*. Its
|
||||
purpose is to turn any expression into a statement. In practical terms, Rust's
|
||||
grammar expects statements to follow other statements. This means that you use
|
||||
semicolons to separate expressions from each other. This means that Rust
|
||||
looks a lot like most other languages that require you to use semicolons
|
||||
at the end of every line, and you will see semicolons at the end of almost
|
||||
every line of Rust code you see.
|
||||
|
||||
What is this exception that makes us say "almost"? You saw it already, in this
|
||||
code:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
let y: i32 = if x == 5 { 10 } else { 15 };
|
||||
```
|
||||
|
||||
Note that I've added the type annotation to `y`, to specify explicitly that I
|
||||
want `y` to be an integer.
|
||||
|
||||
This is not the same as this, which won't compile:
|
||||
|
||||
```{ignore}
|
||||
let x = 5;
|
||||
|
||||
let y: i32 = if x == 5 { 10; } else { 15; };
|
||||
```
|
||||
|
||||
Note the semicolons after the 10 and 15. Rust will give us the following error:
|
||||
|
||||
```text
|
||||
error: mismatched types: expected `i32`, found `()` (expected i32, found ())
|
||||
```
|
||||
|
||||
We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a
|
||||
special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
|
||||
variable of type `i32`. It's only a valid value for variables of the type `()`,
|
||||
which aren't very useful. Remember how we said statements don't return a value?
|
||||
Well, that's the purpose of unit in this case. The semicolon turns any
|
||||
expression into a statement by throwing away its value and returning unit
|
||||
instead.
|
||||
|
||||
There's one more time in which you won't see a semicolon at the end of a line
|
||||
of Rust code. For that, we'll need our next concept: functions.
|
||||
This works because `if` is an expression. The value of the expression is the
|
||||
value of the last expression in whichever branch was chosen. An `if` without an
|
||||
`else` always results in `()` as the value.
|
||||
|
@ -1,27 +1,32 @@
|
||||
% Installing Rust
|
||||
|
||||
The first step to using Rust is to install it! There are a number of ways to
|
||||
install Rust, but the easiest is to use the `rustup` script. If you're on
|
||||
Linux or a Mac, all you need to do is this (note that you don't need to type
|
||||
in the `$`s, they just indicate the start of each command):
|
||||
install Rust, but the easiest is to use the `rustup` script. If you're on Linux
|
||||
or a Mac, all you need to do is this (note that you don't need to type in the
|
||||
`$`s, they just indicate the start of each command):
|
||||
|
||||
```bash
|
||||
$ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh
|
||||
```
|
||||
|
||||
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
|
||||
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
|
||||
If you're concerned about the [potential insecurity][insecurity] of using `curl
|
||||
| sudo sh`, please keep reading and see our disclaimer below. And feel free to
|
||||
use a two-step version of the installation and examine our installation script:
|
||||
|
||||
```bash
|
||||
$ curl -f -L https://static.rust-lang.org/rustup.sh -O
|
||||
$ sudo sh rustup.sh
|
||||
```
|
||||
|
||||
If you're on Windows, please download either the [32-bit
|
||||
installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe)
|
||||
or the [64-bit
|
||||
installer](https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe)
|
||||
and run it.
|
||||
[insecurity]: http://curlpipesh.tumblr.com
|
||||
|
||||
If you're on Windows, please download either the [32-bit installer][win32] or
|
||||
the [64-bit installer][win64] and run it.
|
||||
|
||||
[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
|
||||
[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
|
||||
|
||||
## Uninstalling
|
||||
|
||||
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
|
||||
Not every programming language is great for everyone. Just run the uninstall
|
||||
@ -31,22 +36,20 @@ script:
|
||||
$ sudo /usr/local/lib/rustlib/uninstall.sh
|
||||
```
|
||||
|
||||
If you used the Windows installer, just re-run the `.exe` and it will give you
|
||||
If you used the Windows installer, just re-run the `.msi` and it will give you
|
||||
an uninstall option.
|
||||
|
||||
You can re-run this script any time you want to update Rust. Which, at this
|
||||
point, is often. Rust is still pre-1.0, and so people assume that you're using
|
||||
a very recent Rust.
|
||||
Some people, and somewhat rightfully so, get very upset when we tell you to
|
||||
`curl | sudo sh`. Basically, when you do this, you are trusting that the good
|
||||
people who maintain Rust aren't going to hack your computer and do bad things.
|
||||
That's a good instinct! If you're one of those people, please check out the
|
||||
documentation on [building Rust from Source][from source], or [the official
|
||||
binary downloads][install page]. And we promise that this method will not be
|
||||
the way to install Rust forever: it's just the easiest way to keep people
|
||||
updated while Rust is in its alpha state.
|
||||
|
||||
This brings me to one other point: some people, and somewhat rightfully so, get
|
||||
very upset when we tell you to `curl | sudo sh`. And they should be! Basically,
|
||||
when you do this, you are trusting that the good people who maintain Rust
|
||||
aren't going to hack your computer and do bad things. That's a good instinct!
|
||||
If you're one of those people, please check out the documentation on [building
|
||||
Rust from Source](https://github.com/rust-lang/rust#building-from-source), or
|
||||
[the official binary downloads](http://www.rust-lang.org/install.html). And we
|
||||
promise that this method will not be the way to install Rust forever: it's just
|
||||
the easiest way to keep people updated while Rust is in its alpha state.
|
||||
[from source]: https://github.com/rust-lang/rust#building-from-source
|
||||
[install page]: http://www.rust-lang.org/install.html
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
@ -73,7 +76,7 @@ $ rustc --version
|
||||
You should see the version number, commit hash, commit date and build date:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
|
||||
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
@ -84,10 +87,13 @@ On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
|
||||
to.
|
||||
|
||||
If not, there are a number of places where you can get help. The easiest is
|
||||
[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which
|
||||
you can access through
|
||||
[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click
|
||||
that link, and you'll be chatting with other Rustaceans (a silly nickname we
|
||||
call ourselves), and we can help you out. Other great resources include [the
|
||||
/r/rust subreddit](http://www.reddit.com/r/rust), and [Stack
|
||||
Overflow](http://stackoverflow.com/questions/tagged/rust).
|
||||
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
|
||||
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
|
||||
(a silly nickname we call ourselves), and we can help you out. Other great
|
||||
resources include [the user’s forum][users], and
|
||||
[Stack Overflow][stack overflow].
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[stack overflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
@ -1,7 +0,0 @@
|
||||
% Intermediate
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
@ -291,7 +291,7 @@ If you are trying to execute a closure on an iterator for its side effects,
|
||||
just use `for` instead.
|
||||
|
||||
There are tons of interesting iterator adapters. `take(n)` will return an
|
||||
iterator over the next `n` elements of the original iterator, note that this
|
||||
iterator over the next `n` elements of the original iterator. Note that this
|
||||
has no side effect on the original iterator. Let's try it out with our infinite
|
||||
iterator from before:
|
||||
|
||||
|
4
src/doc/trpl/learn-rust.md
Normal file
4
src/doc/trpl/learn-rust.md
Normal file
@ -0,0 +1,4 @@
|
||||
% Learn Rust
|
||||
|
||||
This section is coming soon! It will eventually have a few tutorials with
|
||||
building real Rust projects, but they are under development.
|
3
src/doc/trpl/lifetimes.md
Normal file
3
src/doc/trpl/lifetimes.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Lifetimes
|
||||
|
||||
Coming soon!
|
@ -1,133 +0,0 @@
|
||||
% Looping
|
||||
|
||||
Looping is the last basic construct that we haven't learned yet in Rust. Rust has
|
||||
two main looping constructs: `for` and `while`.
|
||||
|
||||
## `for`
|
||||
|
||||
The `for` loop is used to loop a particular number of times. Rust's `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust's `for`
|
||||
loop doesn't look like this "C-style" `for` loop:
|
||||
|
||||
```{c}
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
Instead, it looks like this:
|
||||
|
||||
```{rust}
|
||||
for x in 0..10 {
|
||||
println!("{}", x); // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an iterator, which we will discuss in more depth later in the
|
||||
guide. The iterator gives back a series of elements. Each element is one
|
||||
iteration of the loop. That value is then bound to the name `var`, which is
|
||||
valid for the loop body. Once the body is over, the next value is fetched from
|
||||
the iterator, and we loop another time. When there are no more values, the
|
||||
`for` loop is over.
|
||||
|
||||
In our example, `0..10` is an expression that takes a start and an end position,
|
||||
and gives an iterator over those values. The upper bound is exclusive, though,
|
||||
so our loop will print `0` through `9`, not `10`.
|
||||
|
||||
Rust does not have the "C-style" `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers.
|
||||
|
||||
We'll talk more about `for` when we cover *iterators*, later in the Guide.
|
||||
|
||||
## `while`
|
||||
|
||||
The other kind of looping construct in Rust is the `while` loop. It looks like
|
||||
this:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5; // mut x: u32
|
||||
let mut done = false; // mut done: bool
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
`while` loops are the correct choice when you're not sure how many times
|
||||
you need to loop.
|
||||
|
||||
If you need an infinite loop, you may be tempted to write this:
|
||||
|
||||
```{rust,ignore}
|
||||
while true {
|
||||
```
|
||||
|
||||
However, Rust has a dedicated keyword, `loop`, to handle this case:
|
||||
|
||||
```{rust,ignore}
|
||||
loop {
|
||||
```
|
||||
|
||||
Rust's control-flow analysis treats this construct differently than a
|
||||
`while true`, since we know that it will always loop. The details of what
|
||||
that _means_ aren't super important to understand at this stage, but in
|
||||
general, the more information we can give to the compiler, the better it
|
||||
can do with safety and code generation, so you should always prefer
|
||||
`loop` when you plan to loop infinitely.
|
||||
|
||||
## Ending iteration early
|
||||
|
||||
Let's take a look at that `while` loop we had earlier:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5;
|
||||
let mut done = false;
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
We had to keep a dedicated `mut` boolean variable binding, `done`, to know
|
||||
when we should exit out of the loop. Rust has two keywords to help us with
|
||||
modifying iteration: `break` and `continue`.
|
||||
|
||||
In this case, we can write the loop in a better way with `break`:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5;
|
||||
|
||||
loop {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { break; }
|
||||
}
|
||||
```
|
||||
|
||||
We now loop forever with `loop` and use `break` to break out early.
|
||||
|
||||
`continue` is similar, but instead of ending the loop, goes to the next
|
||||
iteration. This will only print the odd numbers:
|
||||
|
||||
```{rust}
|
||||
for x in 0..10 {
|
||||
if x % 2 == 0 { continue; }
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Both `continue` and `break` are valid in both kinds of loops.
|
@ -424,9 +424,240 @@ they are unstable and require feature gates.
|
||||
* `trace_macros!(true)` will enable a compiler message every time a macro is
|
||||
expanded. Use `trace_macros!(false)` later in expansion to turn it off.
|
||||
|
||||
# Further reading
|
||||
# Syntactic requirements
|
||||
|
||||
The [advanced macros chapter][] goes into more detail about macro syntax. It
|
||||
also describes how to share macros between different modules or crates.
|
||||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||
[syntax tree][ast]. This property can be very useful for editors and other
|
||||
tools that process code. It also has a few consequences for the design of
|
||||
Rust's macro system.
|
||||
|
||||
[advanced macros chapter]: advanced-macros.html
|
||||
[ast]: glossary.html#abstract-syntax-tree
|
||||
|
||||
One consequence is that Rust must determine, when it parses a macro invocation,
|
||||
whether the macro stands in for
|
||||
|
||||
* zero or more items,
|
||||
* zero or more methods,
|
||||
* an expression,
|
||||
* a statement, or
|
||||
* a pattern.
|
||||
|
||||
A macro invocation within a block could stand for some items, or for an
|
||||
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
|
||||
macro invocation that stands for items must be either
|
||||
|
||||
* delimited by curly braces, e.g. `foo! { ... }`, or
|
||||
* terminated by a semicolon, e.g. `foo!(...);`
|
||||
|
||||
Another consequence of pre-expansion parsing is that the macro invocation must
|
||||
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
||||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
* `path`: a qualified name. Example: `T::SpecialA`.
|
||||
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
|
||||
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
|
||||
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
|
||||
* `stmt`: a single statement. Example: `let x = 3`.
|
||||
* `block`: a brace-delimited sequence of statements. Example:
|
||||
`{ log(error, "hi"); return 12; }`.
|
||||
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
|
||||
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
|
||||
* `tt`: a single token tree.
|
||||
|
||||
There are additional rules regarding the next token after a metavariable:
|
||||
|
||||
* `expr` variables must be followed by one of: `=> , ;`
|
||||
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
|
||||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
|
||||
be forced to choose between parsing `$t` and parsing `$e`. Changing the
|
||||
invocation syntax to put a distinctive token in front can solve the problem. In
|
||||
this case, you can write `$(T $t:ty)* E $e:exp`.
|
||||
|
||||
[item]: ../reference.html#items
|
||||
|
||||
# Scoping and macro import/export
|
||||
|
||||
Macros are expanded at an early stage in compilation, before name resolution.
|
||||
One downside is that scoping works differently for macros, compared to other
|
||||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
A macro defined within the body of a single `fn`, or anywhere else not at
|
||||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
it controls which macros are loaded from the external crate, e.g.
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use(foo, bar)]
|
||||
extern crate baz;
|
||||
```
|
||||
|
||||
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
||||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
||||
```rust
|
||||
macro_rules! m1 { () => (()) }
|
||||
|
||||
// visible here: m1
|
||||
|
||||
mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 { () => (()) }
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 { () => (()) }
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
#[macro_use]
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 { () => (()) }
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
A further difficulty occurs when a macro is used in multiple crates. Say that
|
||||
`mylib` defines
|
||||
|
||||
```rust
|
||||
pub fn increment(x: u32) -> u32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_a {
|
||||
($x:expr) => ( ::increment($x) )
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_b {
|
||||
($x:expr) => ( ::mylib::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
`inc_a` only works within `mylib`, while `inc_b` only works outside the
|
||||
library. Furthermore, `inc_b` will break if the user imports `mylib` under
|
||||
another name.
|
||||
|
||||
Rust does not (yet) have a hygiene system for crate references, but it does
|
||||
provide a simple workaround for this problem. Within a macro imported from a
|
||||
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
|
||||
By contrast, when a macro is defined and then used in the same crate, `$crate`
|
||||
will expand to nothing. This means we can write
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($x:expr) => ( $crate::increment($x) )
|
||||
}
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
to define a single macro that works both inside and outside our library. The
|
||||
function name will expand to either `::increment` or `::mylib::increment`.
|
||||
|
||||
To keep this system simple and correct, `#[macro_use] extern crate ...` may
|
||||
only appear at the root of your crate, not inside `mod`. This ensures that
|
||||
`$crate` is a single identifier.
|
||||
|
||||
# The deep end
|
||||
|
||||
The introductory chapter mentioned recursive macros, but it did not give the
|
||||
full story. Recursive macros are useful for another reason: Each recursive
|
||||
invocation gives you another opportunity to pattern-match the macro's
|
||||
arguments.
|
||||
|
||||
As an extreme example, it is possible, though hardly advisable, to implement
|
||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||
within Rust's macro system.
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
Exercise: use macros to reduce duplication in the above definition of the
|
||||
`bct!` macro.
|
||||
|
||||
# Procedural macros
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and bugs can be much harder to track down. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
||||
|
@ -1,13 +1,13 @@
|
||||
% Match
|
||||
|
||||
Often, a simple `if`/`else` isn't enough, because you have more than two
|
||||
Often, a simple `if`/`else` isn’t enough, because you have more than two
|
||||
possible options. Also, `else` conditions can get incredibly complicated, so
|
||||
what's the solution?
|
||||
what’s the solution?
|
||||
|
||||
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
|
||||
groupings with something more powerful. Check it out:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
@ -21,11 +21,14 @@ match x {
|
||||
```
|
||||
|
||||
`match` takes an expression and then branches based on its value. Each *arm* of
|
||||
the branch is of the form `val => expression`. When the value matches, that arm's
|
||||
expression will be evaluated. It's called `match` because of the term 'pattern
|
||||
matching', which `match` is an implementation of.
|
||||
the branch is of the form `val => expression`. When the value matches, that arm’s
|
||||
expression will be evaluated. It’s called `match` because of the term ‘pattern
|
||||
matching’, which `match` is an implementation of. There’s an [entire section on
|
||||
patterns][patterns] coming up next, that covers all the options that fit here.
|
||||
|
||||
So what's the big advantage here? Well, there are a few. First of all, `match`
|
||||
[patterns]: patterns.html
|
||||
|
||||
So what’s the big advantage here? Well, there are a few. First of all, `match`
|
||||
enforces *exhaustiveness checking*. Do you see that last arm, the one with the
|
||||
underscore (`_`)? If we remove that arm, Rust will give us an error:
|
||||
|
||||
@ -36,121 +39,24 @@ error: non-exhaustive patterns: `_` not covered
|
||||
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
|
||||
integer, Rust knows that it can have a number of different values – for example,
|
||||
`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses
|
||||
to compile. `_` acts like a *catch-all arm*. If none of the other arms match,
|
||||
to compile. `_` acts like a ‘catch-all arm’. If none of the other arms match,
|
||||
the arm with `_` will, and since we have this catch-all arm, we now have an arm
|
||||
for every possible value of `x`, and so our program will compile successfully.
|
||||
|
||||
`match` statements also destructure enums, as well. Remember this code from the
|
||||
section on enums?
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y);
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can re-write this as a `match`:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
match cmp(x, y) {
|
||||
Ordering::Less => println!("less"),
|
||||
Ordering::Greater => println!("greater"),
|
||||
Ordering::Equal => println!("equal"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This version has way less noise, and it also checks exhaustively to make sure
|
||||
that we have covered all possible variants of `Ordering`. With our `if`/`else`
|
||||
version, if we had forgotten the `Greater` case, for example, our program would
|
||||
have happily compiled. If we forget in the `match`, it will not. Rust helps us
|
||||
make sure to cover all of our bases.
|
||||
|
||||
`match` expressions also allow us to get the values contained in an `enum`
|
||||
(also known as destructuring) as follows:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = OptionalInt::Value(5);
|
||||
let y = OptionalInt::Missing;
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(n) => println!("x is {}", n),
|
||||
OptionalInt::Missing => println!("x is missing!"),
|
||||
}
|
||||
|
||||
match y {
|
||||
OptionalInt::Value(n) => println!("y is {}", n),
|
||||
OptionalInt::Missing => println!("y is missing!"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That is how you can get and use the values contained in `enum`s.
|
||||
It can also allow us to handle errors or unexpected computations; for example, a
|
||||
function that is not guaranteed to be able to compute a result (an `i32` here)
|
||||
could return an `OptionalInt`, and we would handle that value with a `match`.
|
||||
As you can see, `enum` and `match` used together are quite useful!
|
||||
|
||||
`match` is also an expression, which means we can use it on the right-hand
|
||||
side of a `let` binding or directly where an expression is used. We could
|
||||
also implement the previous example like this:
|
||||
side of a `let` binding or directly where an expression is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
println!("{}", match cmp(x, y) {
|
||||
Ordering::Less => "less",
|
||||
Ordering::Greater => "greater",
|
||||
Ordering::Equal => "equal",
|
||||
});
|
||||
}
|
||||
let numer = match x {
|
||||
1 => "one",
|
||||
2 => "two",
|
||||
3 => "three",
|
||||
4 => "four",
|
||||
5 => "five",
|
||||
_ => "something else",
|
||||
};
|
||||
```
|
||||
|
||||
Sometimes, it's a nice pattern.
|
||||
Sometimes, it’s a nice way of converting things.
|
||||
|
@ -4,7 +4,7 @@ Functions are great, but if you want to call a bunch of them on some data, it
|
||||
can be awkward. Consider this code:
|
||||
|
||||
```{rust,ignore}
|
||||
baz(bar(foo(x)));
|
||||
baz(bar(foo)));
|
||||
```
|
||||
|
||||
We would read this left-to right, and so we see "baz bar foo." But this isn't the
|
||||
@ -12,7 +12,7 @@ order that the functions would get called in, that's inside-out: "foo bar baz."
|
||||
Wouldn't it be nice if we could do this instead?
|
||||
|
||||
```{rust,ignore}
|
||||
x.foo().bar().baz();
|
||||
foo.bar().baz();
|
||||
```
|
||||
|
||||
Luckily, as you may have guessed with the leading question, you can! Rust provides
|
||||
@ -47,8 +47,8 @@ This will print `12.566371`.
|
||||
We've made a struct that represents a circle. We then write an `impl` block,
|
||||
and inside it, define a method, `area`. Methods take a special first
|
||||
parameter, of which there are three variants: `self`, `&self`, and `&mut self`.
|
||||
You can think of this first parameter as being the `x` in `x.foo()`. The three
|
||||
variants correspond to the three kinds of thing `x` could be: `self` if it's
|
||||
You can think of this first parameter as being the `foo` in `foo.bar()`. The three
|
||||
variants correspond to the three kinds of things `foo` could be: `self` if it's
|
||||
just a value on the stack, `&self` if it's a reference, and `&mut self` if it's
|
||||
a mutable reference. We should default to using `&self`, as you should prefer
|
||||
borrowing over taking ownership, as well as taking immutable references
|
||||
@ -197,7 +197,7 @@ impl CircleBuilder {
|
||||
}
|
||||
|
||||
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
|
||||
self.x = coordinate;
|
||||
self.y = coordinate;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1,325 +0,0 @@
|
||||
% More Strings
|
||||
|
||||
Strings are an important concept to master in any programming language. If you
|
||||
come from a managed language background, you may be surprised at the complexity
|
||||
of string handling in a systems programming language. Efficient access and
|
||||
allocation of memory for a dynamically sized structure involves a lot of
|
||||
details. Luckily, Rust has lots of tools to help us here.
|
||||
|
||||
A **string** is a sequence of unicode scalar values encoded as a stream of
|
||||
UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences.
|
||||
Additionally, strings are not null-terminated and can contain null bytes.
|
||||
|
||||
Rust has two main types of strings: `&str` and `String`.
|
||||
|
||||
# `&str`
|
||||
|
||||
The first kind is a `&str`. This is pronounced a 'string slice'.
|
||||
String literals are of the type `&str`:
|
||||
|
||||
```
|
||||
let string = "Hello there.";
|
||||
```
|
||||
|
||||
Like any Rust reference, string slices have an associated lifetime. A string
|
||||
literal is a `&'static str`. A string slice can be written without an explicit
|
||||
lifetime in many cases, such as in function arguments. In these cases the
|
||||
lifetime will be inferred:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
```
|
||||
|
||||
Like vector slices, string slices are simply a pointer plus a length. This
|
||||
means that they're a 'view' into an already-allocated string, such as a
|
||||
string literal or a `String`.
|
||||
|
||||
## `str`
|
||||
|
||||
You may occasionally see references to a `str` type, without the `&`. While
|
||||
this type does exist, it’s not something you want to use yourself. Sometimes,
|
||||
people confuse `str` for `String`, and write this:
|
||||
|
||||
```rust
|
||||
struct S {
|
||||
s: str,
|
||||
}
|
||||
```
|
||||
|
||||
This leads to ugly errors:
|
||||
|
||||
```text
|
||||
error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277]
|
||||
note: `str` does not have a constant size known at compile-time
|
||||
```
|
||||
|
||||
Instead, this `struct` should be
|
||||
|
||||
```rust
|
||||
struct S {
|
||||
s: String,
|
||||
}
|
||||
```
|
||||
|
||||
So let’s talk about `String`s.
|
||||
|
||||
# `String`
|
||||
|
||||
A `String` is a heap-allocated string. This string is growable, and is
|
||||
also guaranteed to be UTF-8. `String`s are commonly created by
|
||||
converting from a string slice using the `to_string` method.
|
||||
|
||||
```
|
||||
let mut s = "Hello".to_string();
|
||||
println!("{}", s);
|
||||
|
||||
s.push_str(", world.");
|
||||
println!("{}", s);
|
||||
```
|
||||
|
||||
A reference to a `String` will automatically coerce to a string slice:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(&s);
|
||||
}
|
||||
```
|
||||
|
||||
You can also get a `&str` from a stack-allocated array of bytes:
|
||||
|
||||
```
|
||||
use std::str;
|
||||
|
||||
let x: &[u8] = &[b'a', b'b'];
|
||||
let stack_str: &str = str::from_utf8(x).unwrap();
|
||||
```
|
||||
|
||||
# Best Practices
|
||||
|
||||
## `String` vs. `&str`
|
||||
|
||||
In general, you should prefer `String` when you need ownership, and `&str` when
|
||||
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
|
||||
and `T` vs `&T` in general.
|
||||
|
||||
This means starting off with this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: &str) {
|
||||
```
|
||||
|
||||
and only moving to this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: String) {
|
||||
```
|
||||
|
||||
if you have good reason. It's not polite to hold on to ownership you don't
|
||||
need, and it can make your lifetimes more complex.
|
||||
|
||||
## Generic functions
|
||||
|
||||
To write a function that's generic over types of strings, use `&str`.
|
||||
|
||||
```
|
||||
fn some_string_length(x: &str) -> usize {
|
||||
x.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello, world";
|
||||
|
||||
println!("{}", some_string_length(s));
|
||||
|
||||
let s = "Hello, world".to_string();
|
||||
|
||||
println!("{}", some_string_length(&s));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these lines will print `12`.
|
||||
|
||||
## Indexing strings
|
||||
|
||||
You may be tempted to try to access a certain character of a `String`, like
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
let s = "hello".to_string();
|
||||
|
||||
println!("{}", s[0]);
|
||||
```
|
||||
|
||||
This does not compile. This is on purpose. In the world of UTF-8, direct
|
||||
indexing is basically never what you want to do. The reason is that each
|
||||
character can be a variable number of bytes. This means that you have to iterate
|
||||
through the characters anyway, which is an O(n) operation.
|
||||
|
||||
There's 3 basic levels of unicode (and its encodings):
|
||||
|
||||
- code units, the underlying data type used to store everything
|
||||
- code points/unicode scalar values (char)
|
||||
- graphemes (visible characters)
|
||||
|
||||
Rust provides iterators for each of these situations:
|
||||
|
||||
- `.bytes()` will iterate over the underlying bytes
|
||||
- `.chars()` will iterate over the code points
|
||||
- `.graphemes()` will iterate over each grapheme
|
||||
|
||||
Usually, the `graphemes()` method on `&str` is what you want:
|
||||
|
||||
```
|
||||
# #![feature(unicode)]
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.graphemes(true) {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
c͚̉
|
||||
o̼̩̰͗
|
||||
d͔̆̓ͥ
|
||||
é
|
||||
```
|
||||
|
||||
Note that `l` has the type `&str` here, since a single grapheme can consist of
|
||||
multiple codepoints, so a `char` wouldn't be appropriate.
|
||||
|
||||
This will print out each visible character in turn, as you'd expect: first `u͔`, then
|
||||
`n͈̰̎`, etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.chars() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u
|
||||
͔
|
||||
n
|
||||
̎
|
||||
͈
|
||||
̰
|
||||
i
|
||||
̙
|
||||
̮
|
||||
͚
|
||||
̦
|
||||
c
|
||||
̉
|
||||
͚
|
||||
o
|
||||
͗
|
||||
̼
|
||||
̩
|
||||
̰
|
||||
d
|
||||
̆
|
||||
̓
|
||||
ͥ
|
||||
͔
|
||||
e
|
||||
́
|
||||
```
|
||||
|
||||
You can see how some of them are combining characters, and therefore the output
|
||||
looks a bit odd.
|
||||
|
||||
If you want the individual byte representation of each codepoint, you can use
|
||||
`.bytes()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.bytes() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
```text
|
||||
117
|
||||
205
|
||||
148
|
||||
110
|
||||
204
|
||||
142
|
||||
205
|
||||
136
|
||||
204
|
||||
176
|
||||
105
|
||||
204
|
||||
153
|
||||
204
|
||||
174
|
||||
205
|
||||
154
|
||||
204
|
||||
166
|
||||
99
|
||||
204
|
||||
137
|
||||
205
|
||||
154
|
||||
111
|
||||
205
|
||||
151
|
||||
204
|
||||
188
|
||||
204
|
||||
169
|
||||
204
|
||||
176
|
||||
100
|
||||
204
|
||||
134
|
||||
205
|
||||
131
|
||||
205
|
||||
165
|
||||
205
|
||||
148
|
||||
101
|
||||
204
|
||||
129
|
||||
```
|
||||
|
||||
Many more bytes than graphemes!
|
||||
|
||||
# `Deref` coercions
|
||||
|
||||
References to `String`s will automatically coerce into `&str`s. Like this:
|
||||
|
||||
```
|
||||
fn hello(s: &str) {
|
||||
println!("Hello, {}!", s);
|
||||
}
|
||||
|
||||
let slice = "Steve";
|
||||
let string = "Steve".to_string();
|
||||
|
||||
hello(slice);
|
||||
hello(&string);
|
||||
```
|
3
src/doc/trpl/move-semantics.md
Normal file
3
src/doc/trpl/move-semantics.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Move Semantics
|
||||
|
||||
Coming Soon
|
3
src/doc/trpl/mutability.md
Normal file
3
src/doc/trpl/mutability.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Mutability
|
||||
|
||||
Coming Soon
|
102
src/doc/trpl/nightly-rust.md
Normal file
102
src/doc/trpl/nightly-rust.md
Normal file
@ -0,0 +1,102 @@
|
||||
% Nightly Rust
|
||||
|
||||
Rust provides three distribution channels for Rust: nightly, beta, and stable.
|
||||
Unstable features are only available on nightly Rust. For more details on this
|
||||
process, see ‘[Stability as a deliverable][stability]’.
|
||||
|
||||
[stability]: http://blog.rust-lang.org/2014/10/30/Stability.html
|
||||
|
||||
To install nightly Rust, you can use `rustup.sh`:
|
||||
|
||||
```bash
|
||||
$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh -s -- --channel=nightly
|
||||
```
|
||||
|
||||
If you're concerned about the [potential insecurity][insecurity] of using `curl
|
||||
| sudo sh`, please keep reading and see our disclaimer below. And feel free to
|
||||
use a two-step version of the installation and examine our installation script:
|
||||
|
||||
```bash
|
||||
$ curl -f -L https://static.rust-lang.org/rustup.sh -O
|
||||
$ sudo sh rustup.sh --channel=nightly
|
||||
```
|
||||
|
||||
[insecurity]: http://curlpipesh.tumblr.com
|
||||
|
||||
If you're on Windows, please download either the [32-bit installer][win32] or
|
||||
the [64-bit installer][win64] and run it.
|
||||
|
||||
[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
|
||||
[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
|
||||
|
||||
## Uninstalling
|
||||
|
||||
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
|
||||
Not every programming language is great for everyone. Just run the uninstall
|
||||
script:
|
||||
|
||||
```bash
|
||||
$ sudo /usr/local/lib/rustlib/uninstall.sh
|
||||
```
|
||||
|
||||
If you used the Windows installer, just re-run the `.msi` and it will give you
|
||||
an uninstall option.
|
||||
|
||||
Some people, and somewhat rightfully so, get very upset when we tell you to
|
||||
`curl | sudo sh`. Basically, when you do this, you are trusting that the good
|
||||
people who maintain Rust aren't going to hack your computer and do bad things.
|
||||
That's a good instinct! If you're one of those people, please check out the
|
||||
documentation on [building Rust from Source][from source], or [the official
|
||||
binary downloads][install page]. And we promise that this method will not be
|
||||
the way to install Rust forever: it's just the easiest way to keep people
|
||||
updated while Rust is in its alpha state.
|
||||
|
||||
[from source]: https://github.com/rust-lang/rust#building-from-source
|
||||
[install page]: http://www.rust-lang.org/install.html
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
We extensively test Rust on these platforms, and a few others, too, like
|
||||
Android. But these are the ones most likely to work, as they have the most
|
||||
testing.
|
||||
|
||||
Finally, a comment about Windows. Rust considers Windows to be a first-class
|
||||
platform upon release, but if we're honest, the Windows experience isn't as
|
||||
integrated as the Linux/OS X experience is. We're working on it! If anything
|
||||
does not work, it is a bug. Please let us know if that happens. Each and every
|
||||
commit is tested against Windows just like any other platform.
|
||||
|
||||
If you've got Rust installed, you can open up a shell, and type this:
|
||||
|
||||
```bash
|
||||
$ rustc --version
|
||||
```
|
||||
|
||||
You should see the version number, commit hash, commit date and build date:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
|
||||
This installer also installs a copy of the documentation locally, so you can
|
||||
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
|
||||
On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
|
||||
to.
|
||||
|
||||
If not, there are a number of places where you can get help. The easiest is
|
||||
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
|
||||
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
|
||||
(a silly nickname we call ourselves), and we can help you out. Other great
|
||||
resources include [the user’s forum][users], and [Stack Overflow][stack
|
||||
overflow].
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[stack overflow]: http://stackoverflow.com/questions/tagged/rust
|
@ -103,7 +103,7 @@ necessary functionality for writing idiomatic and effective Rust code.
|
||||
As an example, here is a program that will calculate the dot product of two
|
||||
vectors provided from C, using idiomatic Rust practices.
|
||||
|
||||
```
|
||||
```ignore
|
||||
#![feature(lang_items, start, no_std, core, libc)]
|
||||
#![no_std]
|
||||
|
||||
|
3
src/doc/trpl/operators-and-overloading.md
Normal file
3
src/doc/trpl/operators-and-overloading.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Operators and Overloading
|
||||
|
||||
Coming soon!
|
@ -1,13 +1,16 @@
|
||||
% Patterns
|
||||
|
||||
We've made use of patterns a few times in the guide: first with `let` bindings,
|
||||
then with `match` statements. Let's go on a whirlwind tour of all of the things
|
||||
patterns can do!
|
||||
Patterns are quite common in Rust. We use them in [variable
|
||||
bindings][bindings], [match statements][match], and other places, too. Let’s go
|
||||
on a whirlwind tour of all of the things patterns can do!
|
||||
|
||||
[bindings]: variable-bindings.html
|
||||
[match]: match.html
|
||||
|
||||
A quick refresher: you can match against literals directly, and `_` acts as an
|
||||
*any* case:
|
||||
‘any’ case:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
@ -18,9 +21,11 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
# Multiple patterns
|
||||
|
||||
You can match multiple patterns with `|`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
@ -30,9 +35,11 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
# Ranges
|
||||
|
||||
You can match a range of values with `...`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
@ -43,10 +50,12 @@ match x {
|
||||
|
||||
Ranges are mostly used with integers and single characters.
|
||||
|
||||
If you're matching multiple things, via a `|` or a `...`, you can bind
|
||||
# Bindings
|
||||
|
||||
If you’re matching multiple things, via a `|` or a `...`, you can bind
|
||||
the value to a name with `@`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
@ -55,10 +64,12 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
If you're matching on an enum which has variants, you can use `..` to
|
||||
# Ignoring variants
|
||||
|
||||
If you’re matching on an enum which has variants, you can use `..` to
|
||||
ignore the value and type in the variant:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
@ -72,9 +83,11 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
You can introduce *match guards* with `if`:
|
||||
# Guards
|
||||
|
||||
```{rust}
|
||||
You can introduce ‘match guards’ with `if`:
|
||||
|
||||
```rust
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
@ -89,24 +102,11 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
If you're matching on a pointer, you can use the same syntax as you declared it
|
||||
with. First, `&`:
|
||||
# ref and ref mut
|
||||
|
||||
```{rust}
|
||||
let x = &5;
|
||||
If you want to get a [reference][ref], use the `ref` keyword:
|
||||
|
||||
match x {
|
||||
&val => println!("Got a value: {}", val),
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `val` inside the `match` has type `i32`. In other words, the left-hand
|
||||
side of the pattern destructures the value. If we have `&5`, then in `&val`, `val`
|
||||
would be `5`.
|
||||
|
||||
If you want to get a reference, use the `ref` keyword:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
@ -114,11 +114,13 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
[ref]: references-and-borrowing.html
|
||||
|
||||
Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
|
||||
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
||||
reference, `ref mut` will work in the same way:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let mut x = 5;
|
||||
|
||||
match x {
|
||||
@ -126,10 +128,12 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
If you have a struct, you can destructure it inside of a pattern:
|
||||
# Destructuring
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
If you have a compound data type, like a `struct`, you can destructure it
|
||||
inside of a pattern:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -142,10 +146,9 @@ match origin {
|
||||
}
|
||||
```
|
||||
|
||||
If we only care about some of the values, we don't have to give them all names:
|
||||
If we only care about some of the values, we don’t have to give them all names:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -160,8 +163,7 @@ match origin {
|
||||
|
||||
You can do this kind of match on any member, not just the first:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -174,22 +176,16 @@ match origin {
|
||||
}
|
||||
```
|
||||
|
||||
If you want to match against a slice or array, you can use `&`:
|
||||
This ‘destructuring’ behavior works on any compound data type, like
|
||||
[tuples][tuples] or [enums][enums].
|
||||
|
||||
```{rust}
|
||||
# #![feature(slice_patterns)]
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
[tuples]: primitive-types.html#tuples
|
||||
[enums]: enums.html
|
||||
|
||||
match &v[..] {
|
||||
["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
# Mix and Match
|
||||
|
||||
Whew! That's a lot of different ways to match things, and they can all be
|
||||
mixed and matched, depending on what you're doing:
|
||||
Whew! That’s a lot of different ways to match things, and they can all be
|
||||
mixed and matched, depending on what you’re doing:
|
||||
|
||||
```{rust,ignore}
|
||||
match x {
|
||||
|
@ -1,699 +0,0 @@
|
||||
% Pointers
|
||||
|
||||
Rust's pointers are one of its more unique and compelling features. Pointers
|
||||
are also one of the more confusing topics for newcomers to Rust. They can also
|
||||
be confusing for people coming from other languages that support pointers, such
|
||||
as C++. This guide will help you understand this important topic.
|
||||
|
||||
Be sceptical of non-reference pointers in Rust: use them for a deliberate
|
||||
purpose, not just to make the compiler happy. Each pointer type comes with an
|
||||
explanation about when they are appropriate to use. Default to references
|
||||
unless you're in one of those specific situations.
|
||||
|
||||
You may be interested in the [cheat sheet](#cheat-sheet), which gives a quick
|
||||
overview of the types, names, and purpose of the various pointers.
|
||||
|
||||
# An introduction
|
||||
|
||||
If you aren't familiar with the concept of pointers, here's a short
|
||||
introduction. Pointers are a very fundamental concept in systems programming
|
||||
languages, so it's important to understand them.
|
||||
|
||||
## Pointer Basics
|
||||
|
||||
When you create a new variable binding, you're giving a name to a value that's
|
||||
stored at a particular location on the stack. (If you're not familiar with the
|
||||
*heap* vs. *stack*, please check out [this Stack Overflow
|
||||
question](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap),
|
||||
as the rest of this guide assumes you know the difference.) Like this:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
```
|
||||
|
||||
| location | value |
|
||||
|----------|-------|
|
||||
| 0xd3e030 | 5 |
|
||||
| 0xd3e028 | 8 |
|
||||
|
||||
We're making up memory locations here, they're just sample values. Anyway, the
|
||||
point is that `x`, the name we're using for our variable, corresponds to the
|
||||
memory location `0xd3e030`, and the value at that location is `5`. When we
|
||||
refer to `x`, we get the corresponding value. Hence, `x` is `5`.
|
||||
|
||||
Let's introduce a pointer. In some languages, there is just one type of
|
||||
'pointer,' but in Rust, we have many types. In this case, we'll use a Rust
|
||||
*reference*, which is the simplest kind of pointer.
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
```
|
||||
|
||||
|location | value |
|
||||
|-------- |----------|
|
||||
|0xd3e030 | 5 |
|
||||
|0xd3e028 | 8 |
|
||||
|0xd3e020 | 0xd3e028 |
|
||||
|
||||
See the difference? Rather than contain a value, the value of a pointer is a
|
||||
location in memory. In this case, the location of `y`. `x` and `y` have the
|
||||
type `i32`, but `z` has the type `&i32`. We can print this location using the
|
||||
`{:p}` format string:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{:p}", z);
|
||||
```
|
||||
|
||||
This would print `0xd3e028`, with our fictional memory addresses.
|
||||
|
||||
Because `i32` and `&i32` are different types, we can't, for example, add them
|
||||
together:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{}", x + z);
|
||||
```
|
||||
|
||||
This gives us an error:
|
||||
|
||||
```text
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `_`, found `&_` (expected integral variable, found &-ptr)
|
||||
hello.rs:6 println!("{}", x + z);
|
||||
^
|
||||
```
|
||||
|
||||
We can *dereference* the pointer by using the `*` operator. Dereferencing a
|
||||
pointer means accessing the value at the location stored in the pointer. This
|
||||
will work:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = 8;
|
||||
let z = &y;
|
||||
|
||||
println!("{}", x + *z);
|
||||
```
|
||||
|
||||
It prints `13`.
|
||||
|
||||
That's it! That's all pointers are: they point to some memory location. Not
|
||||
much else to them. Now that we've discussed the *what* of pointers, let's
|
||||
talk about the *why*.
|
||||
|
||||
## Pointer uses
|
||||
|
||||
Rust's pointers are quite useful, but in different ways than in other systems
|
||||
languages. We'll talk about best practices for Rust pointers later in
|
||||
the guide, but here are some ways that pointers are useful in other languages:
|
||||
|
||||
In C, strings are a pointer to a list of `char`s, ending with a null byte.
|
||||
The only way to use strings is to get quite familiar with pointers.
|
||||
|
||||
Pointers are useful to point to memory locations that are not on the stack. For
|
||||
example, our example used two stack variables, so we were able to give them
|
||||
names. But if we allocated some heap memory, we wouldn't have that name
|
||||
available. In C, `malloc` is used to allocate heap memory, and it returns a
|
||||
pointer.
|
||||
|
||||
As a more general variant of the previous two points, any time you have a
|
||||
structure that can change in size, you need a pointer. You can't tell at
|
||||
compile time how much memory to allocate, so you've gotta use a pointer to
|
||||
point at the memory where it will be allocated, and deal with it at run time.
|
||||
|
||||
Pointers are useful in languages that are pass-by-value, rather than
|
||||
pass-by-reference. Basically, languages can make two choices (this is made
|
||||
up syntax, it's not Rust):
|
||||
|
||||
```text
|
||||
func foo(x) {
|
||||
x = 5
|
||||
}
|
||||
|
||||
func main() {
|
||||
i = 1
|
||||
foo(i)
|
||||
// what is the value of i here?
|
||||
}
|
||||
```
|
||||
|
||||
In languages that are pass-by-value, `foo` will get a copy of `i`, and so
|
||||
the original version of `i` is not modified. At the comment, `i` will still be
|
||||
`1`. In a language that is pass-by-reference, `foo` will get a reference to `i`,
|
||||
and therefore, can change its value. At the comment, `i` will be `5`.
|
||||
|
||||
So what do pointers have to do with this? Well, since pointers point to a
|
||||
location in memory...
|
||||
|
||||
```text
|
||||
func foo(&i32 x) {
|
||||
*x = 5
|
||||
}
|
||||
|
||||
func main() {
|
||||
i = 1
|
||||
foo(&i)
|
||||
// what is the value of i here?
|
||||
}
|
||||
```
|
||||
|
||||
Even in a language which is pass by value, `i` will be `5` at the comment. You
|
||||
see, because the argument `x` is a pointer, we do send a copy over to `foo`,
|
||||
but because it points at a memory location, which we then assign to, the
|
||||
original value is still changed. This pattern is called
|
||||
*pass-reference-by-value*. Tricky!
|
||||
|
||||
## Common pointer problems
|
||||
|
||||
We've talked about pointers, and we've sung their praises. So what's the
|
||||
downside? Well, Rust attempts to mitigate each of these kinds of problems,
|
||||
but here are problems with pointers in other languages:
|
||||
|
||||
Uninitialized pointers can cause a problem. For example, what does this program
|
||||
do?
|
||||
|
||||
```{ignore}
|
||||
&int x;
|
||||
*x = 5; // whoops!
|
||||
```
|
||||
|
||||
Who knows? We just declare a pointer, but don't point it at anything, and then
|
||||
set the memory location that it points at to be `5`. But which location? Nobody
|
||||
knows. This might be harmless, and it might be catastrophic.
|
||||
|
||||
When you combine pointers and functions, it's easy to accidentally invalidate
|
||||
the memory the pointer is pointing to. For example:
|
||||
|
||||
```text
|
||||
func make_pointer(): &int {
|
||||
x = 5;
|
||||
|
||||
return &x;
|
||||
}
|
||||
|
||||
func main() {
|
||||
&int i = make_pointer();
|
||||
*i = 5; // uh oh!
|
||||
}
|
||||
```
|
||||
|
||||
`x` is local to the `make_pointer` function, and therefore, is invalid as soon
|
||||
as `make_pointer` returns. But we return a pointer to its memory location, and
|
||||
so back in `main`, we try to use that pointer, and it's a very similar
|
||||
situation to our first one. Setting invalid memory locations is bad.
|
||||
|
||||
As one last example of a big problem with pointers, *aliasing* can be an
|
||||
issue. Two pointers are said to alias when they point at the same location
|
||||
in memory. Like this:
|
||||
|
||||
```text
|
||||
func mutate(&int i, int j) {
|
||||
*i = j;
|
||||
}
|
||||
|
||||
func main() {
|
||||
x = 5;
|
||||
y = &x;
|
||||
z = &x; //y and z are aliased
|
||||
|
||||
|
||||
run_in_new_thread(mutate, y, 1);
|
||||
run_in_new_thread(mutate, z, 100);
|
||||
|
||||
// what is the value of x here?
|
||||
}
|
||||
```
|
||||
|
||||
In this made-up example, `run_in_new_thread` spins up a new thread, and calls
|
||||
the given function name with its arguments. Since we have two threads, and
|
||||
they're both operating on aliases to `x`, we can't tell which one finishes
|
||||
first, and therefore, the value of `x` is actually non-deterministic. Worse,
|
||||
what if one of them had invalidated the memory location they pointed to? We'd
|
||||
have the same problem as before, where we'd be setting an invalid location.
|
||||
|
||||
## Conclusion
|
||||
|
||||
That's a basic overview of pointers as a general concept. As we alluded to
|
||||
before, Rust has different kinds of pointers, rather than just one, and
|
||||
mitigates all of the problems that we talked about, too. This does mean that
|
||||
Rust pointers are slightly more complicated than in other languages, but
|
||||
it's worth it to not have the problems that simple pointers have.
|
||||
|
||||
# References
|
||||
|
||||
The most basic type of pointer that Rust has is called a *reference*. Rust
|
||||
references look like this:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
println!("{}", *y);
|
||||
println!("{:p}", y);
|
||||
println!("{}", y);
|
||||
```
|
||||
|
||||
We'd say "`y` is a reference to `x`." The first `println!` prints out the
|
||||
value of `y`'s referent by using the dereference operator, `*`. The second
|
||||
one prints out the memory location that `y` points to, by using the pointer
|
||||
format string. The third `println!` *also* prints out the value of `y`'s
|
||||
referent, because `println!` will automatically dereference it for us.
|
||||
|
||||
Here's a function that takes a reference:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
You can also use `&` as an operator to create a reference, so we can
|
||||
call this function in two different ways:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
|
||||
fn main() {
|
||||
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
println!("{}", succ(y));
|
||||
println!("{}", succ(&x));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these `println!`s will print out `6`.
|
||||
|
||||
Of course, if this were real code, we wouldn't bother with the reference, and
|
||||
just write:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: i32) -> i32 { x + 1 }
|
||||
```
|
||||
|
||||
References are immutable by default:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
*y = 5; // error: cannot assign to immutable borrowed content `*y`
|
||||
```
|
||||
|
||||
They can be made mutable with `mut`, but only if its referent is also mutable.
|
||||
This works:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
```
|
||||
|
||||
This does not:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = 5;
|
||||
let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable
|
||||
```
|
||||
|
||||
Immutable pointers are allowed to alias:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
let z = &x;
|
||||
```
|
||||
|
||||
Mutable ones, however, are not:
|
||||
|
||||
```{rust,ignore}
|
||||
let mut x = 5;
|
||||
let y = &mut x;
|
||||
let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time
|
||||
```
|
||||
|
||||
Despite their complete safety, a reference's representation at runtime is the
|
||||
same as that of an ordinary pointer in a C program. They introduce zero
|
||||
overhead. The compiler does all safety checks at compile time. The theory that
|
||||
allows for this was originally called *region pointers*. Region pointers
|
||||
evolved into what we know today as *lifetimes*.
|
||||
|
||||
Here's the simple explanation: would you expect this code to compile?
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
println!("{}", x);
|
||||
let x = 5;
|
||||
}
|
||||
```
|
||||
|
||||
Probably not. That's because you know that the name `x` is valid from where
|
||||
it's declared to when it goes out of scope. In this case, that's the end of
|
||||
the `main` function. So you know this code will cause an error. We call this
|
||||
duration a *lifetime*. Let's try a more complex example:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
if x < 10 {
|
||||
let y = &x;
|
||||
|
||||
println!("Oh no: {}", y);
|
||||
return;
|
||||
}
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Here, we're borrowing a pointer to `x` inside of the `if`. The compiler, however,
|
||||
is able to determine that that pointer will go out of scope without `x` being
|
||||
mutated, and therefore, lets us pass. This wouldn't work:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
if x < 10 {
|
||||
let y = &x;
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", y);
|
||||
return;
|
||||
}
|
||||
|
||||
x -= 1;
|
||||
|
||||
println!("Oh no: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
It gives this error:
|
||||
|
||||
```text
|
||||
test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed
|
||||
test.rs:7 x -= 1;
|
||||
^~~~~~
|
||||
test.rs:5:18: 5:19 note: borrow of `x` occurs here
|
||||
test.rs:5 let y = &x;
|
||||
^
|
||||
```
|
||||
|
||||
As you might guess, this kind of analysis is complex for a human, and therefore
|
||||
hard for a computer, too! There is an entire [guide devoted to references, ownership,
|
||||
and lifetimes](ownership.html) that goes into this topic in
|
||||
great detail, so if you want the full details, check that out.
|
||||
|
||||
## Best practices
|
||||
|
||||
In general, prefer stack allocation over heap allocation. Using references to
|
||||
stack allocated information is preferred whenever possible. Therefore,
|
||||
references are the default pointer type you should use, unless you have a
|
||||
specific reason to use a different type. The other types of pointers cover when
|
||||
they're appropriate to use in their own best practices sections.
|
||||
|
||||
Use references when you want to use a pointer, but do not want to take ownership.
|
||||
References just borrow ownership, which is more polite if you don't need the
|
||||
ownership. In other words, prefer:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```{rust}
|
||||
fn succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
As a corollary to that rule, references allow you to accept a wide variety of
|
||||
other pointers, and so are useful so that you don't have to write a number
|
||||
of variants per pointer. In other words, prefer:
|
||||
|
||||
```{rust}
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn box_succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||
|
||||
fn rc_succ(x: Rc<i32>) -> i32 { *x + 1 }
|
||||
```
|
||||
|
||||
Note that the caller of your function will have to modify their calls slightly:
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||
|
||||
let ref_x = &5;
|
||||
let box_x = Box::new(5);
|
||||
let rc_x = Rc::new(5);
|
||||
|
||||
succ(ref_x);
|
||||
succ(&*box_x);
|
||||
succ(&*rc_x);
|
||||
```
|
||||
|
||||
The initial `*` dereferences the pointer, and then `&` takes a reference to
|
||||
those contents.
|
||||
|
||||
# Boxes
|
||||
|
||||
`Box<T>` is Rust's *boxed pointer* type. Boxes provide the simplest form of
|
||||
heap allocation in Rust. Creating a box looks like this:
|
||||
|
||||
```{rust}
|
||||
let x = Box::new(5);
|
||||
```
|
||||
|
||||
Boxes are heap allocated and they are deallocated automatically by Rust when
|
||||
they go out of scope:
|
||||
|
||||
```{rust}
|
||||
{
|
||||
let x = Box::new(5);
|
||||
|
||||
// stuff happens
|
||||
|
||||
} // x is destructed and its memory is free'd here
|
||||
```
|
||||
|
||||
However, boxes do _not_ use reference counting or garbage collection. Boxes are
|
||||
what's called an *affine type*. This means that the Rust compiler, at compile
|
||||
time, determines when the box comes into and goes out of scope, and inserts the
|
||||
appropriate calls there.
|
||||
|
||||
You don't need to fully grok the theory of affine types to grok boxes, though.
|
||||
As a rough approximation, you can treat this Rust code:
|
||||
|
||||
```{rust}
|
||||
{
|
||||
let x = Box::new(5);
|
||||
|
||||
// stuff happens
|
||||
}
|
||||
```
|
||||
|
||||
As being similar to this C code:
|
||||
|
||||
```c
|
||||
{
|
||||
int *x;
|
||||
x = (int *)malloc(sizeof(int));
|
||||
*x = 5;
|
||||
|
||||
// stuff happens
|
||||
|
||||
free(x);
|
||||
}
|
||||
```
|
||||
|
||||
Of course, this is a 10,000 foot view. It leaves out destructors, for example.
|
||||
But the general idea is correct: you get the semantics of `malloc`/`free`, but
|
||||
with some improvements:
|
||||
|
||||
1. It's impossible to allocate the incorrect amount of memory, because Rust
|
||||
figures it out from the types.
|
||||
2. You cannot forget to `free` memory you've allocated, because Rust does it
|
||||
for you.
|
||||
3. Rust ensures that this `free` happens at the right time, when it is truly
|
||||
not used. Use-after-free is not possible.
|
||||
4. Rust enforces that no other writeable pointers alias to this heap memory,
|
||||
which means writing to an invalid pointer is not possible.
|
||||
|
||||
See the section on references or the [ownership guide](ownership.html)
|
||||
for more detail on how lifetimes work.
|
||||
|
||||
Using boxes and references together is very common. For example:
|
||||
|
||||
```{rust}
|
||||
fn add_one(x: &i32) -> i32 {
|
||||
*x + 1
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
println!("{}", add_one(&*x));
|
||||
}
|
||||
```
|
||||
|
||||
In this case, Rust knows that `x` is being *borrowed* by the `add_one()`
|
||||
function, and since it's only reading the value, allows it.
|
||||
|
||||
We can borrow `x` as read-only multiple times, even simultaneously:
|
||||
|
||||
```{rust}
|
||||
fn add(x: &i32, y: &i32) -> i32 {
|
||||
*x + *y
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
println!("{}", add(&*x, &*x));
|
||||
println!("{}", add(&*x, &*x));
|
||||
}
|
||||
```
|
||||
|
||||
We can mutably borrow `x` multiple times, but only if x itself is mutable, and
|
||||
it may not be *simultaneously* borrowed:
|
||||
|
||||
```{rust,ignore}
|
||||
fn increment(x: &mut i32) {
|
||||
*x += 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// If variable x is not "mut", this will not compile
|
||||
let mut x = Box::new(5);
|
||||
|
||||
increment(&mut x);
|
||||
increment(&mut x);
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Notice the signature of `increment()` requests a mutable reference.
|
||||
|
||||
## Best practices
|
||||
|
||||
Boxes are most appropriate to use when defining recursive data structures.
|
||||
|
||||
### Recursive data structures
|
||||
|
||||
Sometimes, you need a recursive data structure. The simplest is known as a
|
||||
*cons list*:
|
||||
|
||||
|
||||
```{rust}
|
||||
#[derive(Debug)]
|
||||
enum List<T> {
|
||||
Cons(T, Box<List<T>>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))));
|
||||
println!("{:?}", list);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
Cons(1, Box(Cons(2, Box(Cons(3, Box(Nil))))))
|
||||
```
|
||||
|
||||
The reference to another `List` inside of the `Cons` enum variant must be a box,
|
||||
because we don't know the length of the list. Because we don't know the length,
|
||||
we don't know the size, and therefore, we need to heap allocate our list.
|
||||
|
||||
Working with recursive or other unknown-sized data structures is the primary
|
||||
use-case for boxes.
|
||||
|
||||
# Rc and Arc
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Raw Pointers
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Creating your own Pointers
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
## Best practices
|
||||
|
||||
This part is coming soon.
|
||||
|
||||
# Patterns and `ref`
|
||||
|
||||
When you're trying to match something that's stored in a pointer, there may be
|
||||
a situation where matching directly isn't the best option available. Let's see
|
||||
how to properly handle this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn possibly_print(x: &Option<String>) {
|
||||
match *x {
|
||||
// BAD: cannot move out of a `&`
|
||||
Some(s) => println!("{}", s)
|
||||
|
||||
// GOOD: instead take a reference into the memory of the `Option`
|
||||
Some(ref s) => println!("{}", *s),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ref s` here means that `s` will be of type `&String`, rather than type
|
||||
`String`.
|
||||
|
||||
This is important when the type you're trying to get access to has a destructor
|
||||
and you don't want to move it, you just want a reference to it.
|
||||
|
||||
# Cheat Sheet
|
||||
|
||||
Here's a quick rundown of Rust's pointer types:
|
||||
|
||||
| Type | Name | Summary |
|
||||
|--------------|---------------------|---------------------------------------------------------------------|
|
||||
| `&T` | Reference | Allows one or more references to read `T` |
|
||||
| `&mut T` | Mutable Reference | Allows a single reference to read and write `T` |
|
||||
| `Box<T>` | Box | Heap allocated `T` with a single owner that may read and write `T`. |
|
||||
| `Rc<T>` | "arr cee" pointer | Heap allocated `T` with many readers |
|
||||
| `Arc<T>` | Arc pointer | Same as above, but safe sharing across threads |
|
||||
| `*const T` | Raw pointer | Unsafe read access to `T` |
|
||||
| `*mut T` | Mutable raw pointer | Unsafe read and write access to `T` |
|
||||
|
||||
# Related resources
|
||||
|
||||
* [API documentation for Box](../std/boxed/index.html)
|
||||
* [Ownership guide](ownership.html)
|
||||
* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system
|
268
src/doc/trpl/primitive-types.md
Normal file
268
src/doc/trpl/primitive-types.md
Normal file
@ -0,0 +1,268 @@
|
||||
% Primitive Types
|
||||
|
||||
The Rust language has a number of types that are considered ‘primitive’. This
|
||||
means that they’re built-in to the language. Rust is structured in such a way
|
||||
that the standard library also provides a number of useful types built on top
|
||||
of these ones, as well, but these are the most primitive.
|
||||
|
||||
# Booleans
|
||||
|
||||
Rust has a built in boolean type, named `bool`. It has two values, `true` and `false`:
|
||||
|
||||
```rust
|
||||
let x = true;
|
||||
|
||||
let y: bool = false;
|
||||
```
|
||||
|
||||
A common use of booleans is in [`if` statements][if].
|
||||
|
||||
[if]: if.html
|
||||
|
||||
You can find more documentation for `bool`s [in the standard library
|
||||
documentation][bool].
|
||||
|
||||
[bool]: ../std/primitive.bool.html
|
||||
|
||||
# `char`
|
||||
|
||||
The `char` type represents a single Unicode scalar value. You can create `char`s
|
||||
with a single tick: (`'`)
|
||||
|
||||
```rust
|
||||
let x = 'x';
|
||||
let two_hearts = '💕';
|
||||
```
|
||||
|
||||
Unlike some other languages, this means that Rust’s `char` is not a single byte,
|
||||
but four.
|
||||
|
||||
You can find more documentation for `char`s [in the standard library
|
||||
documentation][char].
|
||||
|
||||
[char]: ../std/primitive.char.html
|
||||
|
||||
# Numeric types
|
||||
|
||||
Rust has a variety of numeric types in a few categories: signed and unsigned,
|
||||
fixed and variable, floating-point and integer.
|
||||
|
||||
These types consist of two parts: the category, and the size. For example,
|
||||
`u16` is an unsigned type with sixteen bits of size. More bits lets you have
|
||||
bigger numbers.
|
||||
|
||||
If a number literal has nothing to cause its type to be inferred, it defaults:
|
||||
|
||||
```rust
|
||||
let x = 42; // x has type i32
|
||||
|
||||
let y = 1.0; // y has type f64
|
||||
```
|
||||
|
||||
Here’s a list of the different numeric types, with links to their documentation
|
||||
in the standard library:
|
||||
|
||||
* [i16](../std/primitive.i16.html)
|
||||
* [i32](../std/primitive.i32.html)
|
||||
* [i64](../std/primitive.i64.html)
|
||||
* [i8](../std/primitive.i8.html)
|
||||
* [u16](../std/primitive.u16.html)
|
||||
* [u32](../std/primitive.u32.html)
|
||||
* [u64](../std/primitive.u64.html)
|
||||
* [u8](../std/primitive.u8.html)
|
||||
* [isize](../std/primitive.isize.html)
|
||||
* [usize](../std/primitive.usize.html)
|
||||
* [f32](../std/primitive.f32.html)
|
||||
* [f64](../std/primitive.f64.html)
|
||||
|
||||
Let’s go over them by category:
|
||||
|
||||
## Signed and Unsigned
|
||||
|
||||
Integer types come in two varieties: signed and unsigned. To understand the
|
||||
difference, let’s consider a number with four bits of size. A signed, four-bit
|
||||
number would let you store numbers from `-8` to `+7`. Signed numbers use
|
||||
‘two’s compliment representation’. An unsigned four bit number, since it does
|
||||
not need to store negatives, can store values from `0` to `+15`.
|
||||
|
||||
Unsigned types use a `u` for their category, and signed types use `i`. The `i`
|
||||
is for ‘integer’. So `u8` is an eight-bit unsigned number, and `i8` is an
|
||||
eight-bit signed number.
|
||||
|
||||
## Fixed size types
|
||||
|
||||
Fixed size types have a specific number of bits in their representation. Valid
|
||||
bit sizes are `8`, `16`, `32`, and `64`. So, `u32` is an unsigned, 32-bit integer,
|
||||
and `i64` is a signed, 64-bit integer.
|
||||
|
||||
## Variable sized types
|
||||
|
||||
Rust also provides types whose size depends on the size of a pointer of the
|
||||
underlying machine. These types have ‘size’ as the category, and come in signed
|
||||
and unsigned varieties. This makes for two types: `isize` and `usize`.
|
||||
|
||||
## Floating-point types
|
||||
|
||||
Rust also two floating point types: `f32` and `f64`. These correspond to
|
||||
IEEE-754 single and double precision numbers.
|
||||
|
||||
# Arrays
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the *array*, a fixed-size list of elements of the
|
||||
same type. By default, arrays are immutable.
|
||||
|
||||
```rust
|
||||
let a = [1, 2, 3]; // a: [i32; 3]
|
||||
let mut m = [1, 2, 3]; // m: [i32; 3]
|
||||
```
|
||||
|
||||
Arrays have type `[T; N]`. We’ll talk about this `T` notation [in the generics
|
||||
section][generics]. The `N` is a compile-time constant, for the length of the
|
||||
array.
|
||||
|
||||
There’s a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0`:
|
||||
|
||||
```rust
|
||||
let a = [0; 20]; // a: [i32; 20]
|
||||
```
|
||||
|
||||
You can get the number of elements in an array `a` with `a.len()`:
|
||||
|
||||
```rust
|
||||
let a = [1, 2, 3];
|
||||
|
||||
println!("a has {} elements", a.len());
|
||||
```
|
||||
|
||||
You can access a particular element of an array with *subscript notation*:
|
||||
|
||||
```rust
|
||||
let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3]
|
||||
|
||||
println!("The second name is: {}", names[1]);
|
||||
```
|
||||
|
||||
Subscripts start at zero, like in most programming languages, so the first name
|
||||
is `names[0]` and the second name is `names[1]`. The above example prints
|
||||
`The second name is: Brian`. If you try to use a subscript that is not in the
|
||||
array, you will get an error: array access is bounds-checked at run-time. Such
|
||||
errant access is the source of many bugs in other systems programming
|
||||
languages.
|
||||
|
||||
You can find more documentation for `array`s [in the standard library
|
||||
documentation][array].
|
||||
|
||||
[array]: ../std/primitive.array.html
|
||||
|
||||
# Slices
|
||||
|
||||
A ‘slice’ is a reference to (or “view” into) another data structure. They are
|
||||
useful for allowing safe, efficient access to a portion of an array without
|
||||
copying. For example, you might want to reference just one line of a file read
|
||||
into memory. By nature, a slice is not created directly, but from an existing
|
||||
variable. Slices have a length, can be mutable or not, and in many ways behave
|
||||
like arrays:
|
||||
|
||||
```rust
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||
```
|
||||
|
||||
Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
||||
[generics][generics].
|
||||
|
||||
[generics]: generics.html
|
||||
|
||||
You can find more documentation for `slices`s [in the standard library
|
||||
documentation][slice].
|
||||
|
||||
[slice]: ../std/primitive.slice.html
|
||||
|
||||
# `str`
|
||||
|
||||
Rust’s `str` type is the most primitive string type. As an [unsized type][dst],
|
||||
it’s not very useful by itself, but becomes useful when placed behind a reference,
|
||||
like [`&str`][strings]. As such, we’ll just leave it at that.
|
||||
|
||||
[dst]: unsized-types.html
|
||||
[strings]: strings.html
|
||||
|
||||
You can find more documentation for `str` [in the standard library
|
||||
documentation][str].
|
||||
|
||||
[str]: ../std/primitive.str.html
|
||||
|
||||
# Tuples
|
||||
|
||||
A tuple is an ordered list of fixed size. Like this:
|
||||
|
||||
```rust
|
||||
let x = (1, "hello");
|
||||
```
|
||||
|
||||
The parentheses and commas form this two-length tuple. Here’s the same code, but
|
||||
with the type annotated:
|
||||
|
||||
```rust
|
||||
let x: (i32, &str) = (1, "hello");
|
||||
```
|
||||
|
||||
As you can see, the type of a tuple looks just like the tuple, but with each
|
||||
position having a type name rather than the value. Careful readers will also
|
||||
note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
|
||||
In systems programming languages, strings are a bit more complex than in other
|
||||
languages. For now, just read `&str` as a *string slice*, and we’ll learn more
|
||||
soon.
|
||||
|
||||
You can access the fields in a tuple through a *destructuring let*. Here’s
|
||||
an example:
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
||||
println!("x is {}", x);
|
||||
```
|
||||
|
||||
Remember [before][let] when I said the left-hand side of a `let` statement was more
|
||||
powerful than just assigning a binding? Here we are. We can put a pattern on
|
||||
the left-hand side of the `let`, and if it matches up to the right-hand side,
|
||||
we can assign multiple bindings at once. In this case, `let` "destructures,"
|
||||
or "breaks up," the tuple, and assigns the bits to three bindings.
|
||||
|
||||
[let]: variable-bindings.html
|
||||
|
||||
This pattern is very powerful, and we’ll see it repeated more later.
|
||||
|
||||
There are also a few things you can do with a tuple as a whole, without
|
||||
destructuring. You can assign one tuple into another, if they have the same
|
||||
contained types and [arity]. Tuples have the same arity when they have the same
|
||||
length.
|
||||
|
||||
[arity]: glossary.html#arity
|
||||
|
||||
```rust
|
||||
let mut x = (1, 2); // x: (i32, i32)
|
||||
let y = (2, 3); // y: (i32, i32)
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
You can find more documentation for tuples [in the standard library
|
||||
documentation][tuple].
|
||||
|
||||
[tuple]: ../std/primitive.tuple.html
|
||||
|
||||
# Functions
|
||||
|
||||
Functions also have a type! They look like this:
|
||||
|
||||
```
|
||||
fn foo(x: i32) -> i32 { x }
|
||||
|
||||
let x: fn(i32) -> i32 = foo;
|
||||
```
|
||||
|
||||
In this case, `x` is a ‘function pointer’ to a function that takes an `i32` and
|
||||
returns an `i32`.
|
3
src/doc/trpl/references-and-borrowing.md
Normal file
3
src/doc/trpl/references-and-borrowing.md
Normal file
@ -0,0 +1,3 @@
|
||||
% References and Borrowing
|
||||
|
||||
Coming Soon!
|
18
src/doc/trpl/slice-patterns.md
Normal file
18
src/doc/trpl/slice-patterns.md
Normal file
@ -0,0 +1,18 @@
|
||||
% Slice patterns
|
||||
|
||||
If you want to match against a slice or array, you can use `&` with the
|
||||
`slice_patterns` feature:
|
||||
|
||||
```rust
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
|
||||
match &v[..] {
|
||||
["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
3
src/doc/trpl/static.md
Normal file
3
src/doc/trpl/static.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `static`
|
||||
|
||||
Coming soon!
|
89
src/doc/trpl/structs.md
Normal file
89
src/doc/trpl/structs.md
Normal file
@ -0,0 +1,89 @@
|
||||
% Structs
|
||||
|
||||
Structs are a way of creating more complex datatypes. For example, if we were
|
||||
doing calculations involving coordinates in 2D space, we would need both an `x`
|
||||
and a `y` value:
|
||||
|
||||
```rust
|
||||
let origin_x = 0;
|
||||
let origin_y = 0;
|
||||
```
|
||||
|
||||
A struct lets us combine these two into a single, unified datatype:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let origin = Point { x: 0, y: 0 }; // origin: Point
|
||||
|
||||
println!("The origin is at ({}, {})", origin.x, origin.y);
|
||||
}
|
||||
```
|
||||
|
||||
There’s a lot going on here, so let’s break it down. We declare a struct with
|
||||
the `struct` keyword, and then with a name. By convention, structs begin with a
|
||||
capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn't need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
println!("The point is at ({}, {})", point.x, point.y);
|
||||
}
|
||||
```
|
||||
|
||||
This will print `The point is at (5, 0)`.
|
||||
|
||||
Rust does not support field mutability at the language level, so you cannot
|
||||
write something like this:
|
||||
|
||||
```rust,ignore
|
||||
struct Point {
|
||||
mut x: i32,
|
||||
y: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Mutability is a property of the binding, not of the structure itself. If you’re
|
||||
used to field-level mutability, this may seem strange at first, but it
|
||||
significantly simplifies things. It even lets you make things mutable for a short
|
||||
time only:
|
||||
|
||||
|
||||
```rust,ignore
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
let point = point; // this new binding can’t change now
|
||||
|
||||
point.y = 6; // this causes an error
|
||||
}
|
||||
```
|
10
src/doc/trpl/syntax-and-semantics.md
Normal file
10
src/doc/trpl/syntax-and-semantics.md
Normal file
@ -0,0 +1,10 @@
|
||||
% Syntax and Semantics
|
||||
|
||||
This section breaks Rust down into small chunks, one for each concept.
|
||||
|
||||
If you’d like to learn Rust from the bottom up, reading this in order is a
|
||||
great way to do that.
|
||||
|
||||
These sections also form a reference for each concept, so if you’re reading
|
||||
another tutorial and find something confusing, you can find it explained
|
||||
somewhere in here.
|
@ -382,7 +382,7 @@ pub fn add_two(a: i32) -> i32 {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
3
src/doc/trpl/the-stack-and-the-heap.md
Normal file
3
src/doc/trpl/the-stack-and-the-heap.md
Normal file
@ -0,0 +1,3 @@
|
||||
% The Stack and the Heap
|
||||
|
||||
Coming Soon
|
@ -1,91 +0,0 @@
|
||||
% Tracing Macros
|
||||
|
||||
The `trace_macros` feature allows you to use a special feature: tracing macro
|
||||
invocations.
|
||||
|
||||
In the advanced macros chapter, we defined a `bct` macro:
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
```
|
||||
|
||||
This is pretty complex! we can see the output
|
||||
|
||||
```rust,ignore
|
||||
#![feature(trace_macros)]
|
||||
|
||||
macro_rules! bct {
|
||||
// cmd 0: d ... => ...
|
||||
(0, $($ps:tt),* ; $_d:tt)
|
||||
=> (bct!($($ps),*, 0 ; ));
|
||||
(0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 0 ; $($ds),*));
|
||||
|
||||
// cmd 1p: 1 ... => 1 ... p
|
||||
(1, $p:tt, $($ps:tt),* ; 1)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $p));
|
||||
(1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));
|
||||
|
||||
// cmd 1p: 0 ... => 0 ...
|
||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
|
||||
// halt on empty data string
|
||||
( $($ps:tt),* ; )
|
||||
=> (());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
trace_macros!(true);
|
||||
|
||||
bct!(0, 0, 1, 1, 1 ; 1, 0, 1);
|
||||
}
|
||||
```
|
||||
|
||||
This will print out a wall of text:
|
||||
|
||||
```text
|
||||
bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 1 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 }
|
||||
bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 }
|
||||
bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 }
|
||||
bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 }
|
||||
```
|
||||
|
||||
And eventually, error:
|
||||
|
||||
```text
|
||||
18:45 error: recursion limit reached while expanding the macro `bct`
|
||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
The `trace_macros!` call is what produces this output, showing how we match
|
||||
each time.
|
@ -1,4 +1,4 @@
|
||||
% Static and Dynamic Dispatch
|
||||
% Trait Objects
|
||||
|
||||
When code involves polymorphism, there needs to be a mechanism to determine
|
||||
which specific version is actually run. This is called 'dispatch.' There are
|
@ -229,8 +229,6 @@ everything is fine:
|
||||
|
||||
```{rust}
|
||||
# #![feature(core)]
|
||||
use shapes::HasArea;
|
||||
|
||||
mod shapes {
|
||||
use std::f64::consts;
|
||||
|
||||
@ -251,6 +249,7 @@ mod shapes {
|
||||
}
|
||||
}
|
||||
|
||||
use shapes::HasArea;
|
||||
|
||||
fn main() {
|
||||
let c = shapes::Circle {
|
||||
@ -274,8 +273,8 @@ not, because both the trait and the type aren't in our crate.
|
||||
|
||||
One last thing about traits: generic functions with a trait bound use
|
||||
*monomorphization* (*mono*: one, *morph*: form), so they are statically
|
||||
dispatched. What's that mean? Check out the chapter on [static and dynamic
|
||||
dispatch](static-and-dynamic-dispatch.html) for more.
|
||||
dispatched. What's that mean? Check out the chapter on [trait
|
||||
objects](trait-objects.html) for more.
|
||||
|
||||
## Multiple trait bounds
|
||||
|
||||
@ -390,81 +389,6 @@ This shows off the additional feature of `where` clauses: they allow bounds
|
||||
where the left-hand side is an arbitrary type (`i32` in this case), not just a
|
||||
plain type parameter (like `T`).
|
||||
|
||||
## Our `inverse` Example
|
||||
|
||||
Back in [Generics](generics.html), we were trying to write code like this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn inverse<T>(x: T) -> Result<T, String> {
|
||||
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0 / x)
|
||||
}
|
||||
```
|
||||
|
||||
If we try to compile it, we get this error:
|
||||
|
||||
```text
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
This is because `T` is too generic: we don't know if a random `T` can be
|
||||
compared. For that, we can use trait bounds. It doesn't quite work, but try
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn inverse<T: PartialEq>(x: T) -> Result<T, String> {
|
||||
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0 / x)
|
||||
}
|
||||
```
|
||||
|
||||
You should get this error:
|
||||
|
||||
```text
|
||||
error: mismatched types:
|
||||
expected `T`,
|
||||
found `_`
|
||||
(expected type parameter,
|
||||
found floating-point variable)
|
||||
```
|
||||
|
||||
So this won't work. While our `T` is `PartialEq`, we expected to have another `T`,
|
||||
but instead, we found a floating-point variable. We need a different bound. `Float`
|
||||
to the rescue:
|
||||
|
||||
```
|
||||
# #![feature(std_misc)]
|
||||
use std::num::Float;
|
||||
|
||||
fn inverse<T: Float>(x: T) -> Result<T, String> {
|
||||
if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
|
||||
|
||||
let one: T = Float::one();
|
||||
Ok(one / x)
|
||||
}
|
||||
```
|
||||
|
||||
We've had to replace our generic `0.0` and `1.0` with the appropriate methods
|
||||
from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
|
||||
works just fine:
|
||||
|
||||
```
|
||||
# #![feature(std_misc)]
|
||||
# use std::num::Float;
|
||||
# fn inverse<T: Float>(x: T) -> Result<T, String> {
|
||||
# if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
|
||||
# let one: T = Float::one();
|
||||
# Ok(one / x)
|
||||
# }
|
||||
println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32));
|
||||
println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
|
||||
|
||||
println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
|
||||
println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
|
||||
```
|
||||
|
||||
## Default methods
|
||||
|
||||
There's one last feature of traits we should cover: default methods. It's
|
||||
|
56
src/doc/trpl/tuple-structs.md
Normal file
56
src/doc/trpl/tuple-structs.md
Normal file
@ -0,0 +1,56 @@
|
||||
% Tuple Structs
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
||||
it allows you to create a new type, distinct from that of its contained value
|
||||
and expressing its own semantic meaning:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
3
src/doc/trpl/type-aliases.md
Normal file
3
src/doc/trpl/type-aliases.md
Normal file
@ -0,0 +1,3 @@
|
||||
% `type` Aliases
|
||||
|
||||
Coming soon
|
3
src/doc/trpl/ufcs.md
Normal file
3
src/doc/trpl/ufcs.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Universal Function Call Syntax
|
||||
|
||||
Coming soon
|
@ -1,4 +1,4 @@
|
||||
% Unsafe and Low-Level Code
|
||||
% Unsafe Code
|
||||
|
||||
# Introduction
|
||||
|
3
src/doc/trpl/unsized-types.md
Normal file
3
src/doc/trpl/unsized-types.md
Normal file
@ -0,0 +1,3 @@
|
||||
% Unsized Types
|
||||
|
||||
Coming Soon!
|
@ -1 +0,0 @@
|
||||
% Unstable Rust
|
@ -1,44 +1,48 @@
|
||||
% Variable Bindings
|
||||
|
||||
The first thing we'll learn about are *variable bindings*. They look like this:
|
||||
Vitually every non-’Hello World’ Rust program uses *variable bindings*. They
|
||||
look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
}
|
||||
```
|
||||
|
||||
Putting `fn main() {` in each example is a bit tedious, so we'll leave that out
|
||||
in the future. If you're following along, make sure to edit your `main()`
|
||||
function, rather than leaving it off. Otherwise, you'll get an error.
|
||||
Putting `fn main() {` in each example is a bit tedious, so we’ll leave that out
|
||||
in the future. If you’re following along, make sure to edit your `main()`
|
||||
function, rather than leaving it off. Otherwise, you’ll get an error.
|
||||
|
||||
In many languages, this is called a *variable*. But Rust's variable bindings
|
||||
have a few tricks up their sleeves. Rust has a very powerful feature called
|
||||
*pattern matching* that we'll get into detail with later, but the left
|
||||
hand side of a `let` expression is a full pattern, not just a variable name.
|
||||
This means we can do things like:
|
||||
In many languages, this is called a *variable*, but Rust’s variable bindings
|
||||
have a few tricks up their sleeves. For example the left-hand side of a `let`
|
||||
expression is a ‘[pattern][pattern]’, not just a variable name. This means we
|
||||
can do things like:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let (x, y) = (1, 2);
|
||||
```
|
||||
|
||||
After this expression is evaluated, `x` will be one, and `y` will be two.
|
||||
Patterns are really powerful, but this is about all we can do with them so far.
|
||||
So let's just keep this in the back of our minds as we go forward.
|
||||
Patterns are really powerful, and have [their own section][pattern] in the
|
||||
book. We don’t need those features for now, so we’ll just keep this in the back
|
||||
of our minds as we go forward.
|
||||
|
||||
[pattern]: patterns.html
|
||||
|
||||
Rust is a statically typed language, which means that we specify our types up
|
||||
front. So why does our first example compile? Well, Rust has this thing called
|
||||
*type inference*. If it can figure out what the type of something is, Rust
|
||||
doesn't require you to actually type it out.
|
||||
front, and they’re checked at compile time. So why does our first example
|
||||
compile? Well, Rust has this thing called ‘type inference’. If it can figure
|
||||
out what the type of something is, Rust doesn’t require you to actually type it
|
||||
out.
|
||||
|
||||
We can add the type if we want to, though. Types come after a colon (`:`):
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x: i32 = 5;
|
||||
```
|
||||
|
||||
If I asked you to read this out loud to the rest of the class, you'd say "`x`
|
||||
is a binding with the type `i32` and the value `five`."
|
||||
If I asked you to read this out loud to the rest of the class, you’d say “`x`
|
||||
is a binding with the type `i32` and the value `five`.”
|
||||
|
||||
In this case we chose to represent `x` as a 32-bit signed integer. Rust has
|
||||
many different primitive integer types. They begin with `i` for signed integers
|
||||
@ -48,19 +52,20 @@ bits.
|
||||
In future examples, we may annotate the type in a comment. The examples will
|
||||
look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5; // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
Note the similarities between this annotation and the syntax you use with `let`.
|
||||
Including these kinds of comments is not idiomatic Rust, but we'll occasionally
|
||||
include them to help you understand what the types that Rust infers are.
|
||||
Note the similarities between this annotation and the syntax you use with
|
||||
`let`. Including these kinds of comments is not idiomatic Rust, but we'll
|
||||
occasionally include them to help you understand what the types that Rust
|
||||
infers are.
|
||||
|
||||
By default, bindings are *immutable*. This code will not compile:
|
||||
|
||||
```{ignore}
|
||||
```rust,ignore
|
||||
let x = 5;
|
||||
x = 10;
|
||||
```
|
||||
@ -75,30 +80,30 @@ error: re-assignment of immutable variable `x`
|
||||
|
||||
If you want a binding to be mutable, you can use `mut`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let mut x = 5; // mut x: i32
|
||||
x = 10;
|
||||
```
|
||||
|
||||
There is no single reason that bindings are immutable by default, but we can
|
||||
think about it through one of Rust's primary focuses: safety. If you forget to
|
||||
think about it through one of Rust’s primary focuses: safety. If you forget to
|
||||
say `mut`, the compiler will catch it, and let you know that you have mutated
|
||||
something you may not have intended to mutate. If bindings were mutable by
|
||||
default, the compiler would not be able to tell you this. If you _did_ intend
|
||||
mutation, then the solution is quite easy: add `mut`.
|
||||
|
||||
There are other good reasons to avoid mutable state when possible, but they're
|
||||
There are other good reasons to avoid mutable state when possible, but they’re
|
||||
out of the scope of this guide. In general, you can often avoid explicit
|
||||
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
|
||||
what you need, so it's not verboten.
|
||||
what you need, so it’s not verboten.
|
||||
|
||||
Let's get back to bindings. Rust variable bindings have one more aspect that
|
||||
Let’s get back to bindings. Rust variable bindings have one more aspect that
|
||||
differs from other languages: bindings are required to be initialized with a
|
||||
value before you're allowed to use them.
|
||||
|
||||
Let's try it out. Change your `src/main.rs` file to look like this:
|
||||
Let’s try it out. Change your `src/main.rs` file to look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
@ -106,21 +111,22 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
You can use `cargo build` on the command line to build it. You'll get a warning,
|
||||
but it will still print "Hello, world!":
|
||||
You can use `cargo build` on the command line to build it. You’ll get a
|
||||
warning, but it will still print "Hello, world!":
|
||||
|
||||
```text
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)]
|
||||
on by default
|
||||
src/main.rs:2 let x: i32;
|
||||
^
|
||||
```
|
||||
|
||||
Rust warns us that we never use the variable binding, but since we never use it,
|
||||
no harm, no foul. Things change if we try to actually use this `x`, however. Let's
|
||||
do that. Change your program to look like this:
|
||||
Rust warns us that we never use the variable binding, but since we never use
|
||||
it, no harm, no foul. Things change if we try to actually use this `x`,
|
||||
however. Let’s do that. Change your program to look like this:
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
@ -128,9 +134,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
And try to build it. You'll get an error:
|
||||
And try to build it. You’ll get an error:
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x`
|
||||
@ -144,18 +150,20 @@ error: aborting due to previous error
|
||||
Could not compile `hello_world`.
|
||||
```
|
||||
|
||||
Rust will not let us use a value that has not been initialized. Next, let's
|
||||
Rust will not let us use a value that has not been initialized. Next, let’s
|
||||
talk about this stuff we've added to `println!`.
|
||||
|
||||
If you include two curly braces (`{}`, some call them moustaches...) in your
|
||||
string to print, Rust will interpret this as a request to interpolate some sort
|
||||
of value. *String interpolation* is a computer science term that means "stick
|
||||
in the middle of a string." We add a comma, and then `x`, to indicate that we
|
||||
want `x` to be the value we're interpolating. The comma is used to separate
|
||||
arguments we pass to functions and macros, if you're passing more than one.
|
||||
want `x` to be the value we’re interpolating. The comma is used to separate
|
||||
arguments we pass to functions and macros, if you’re passing more than one.
|
||||
|
||||
When you just use the curly braces, Rust will attempt to display the
|
||||
value in a meaningful way by checking out its type. If you want to specify the
|
||||
format in a more detailed manner, there are a [wide number of options
|
||||
available](../std/fmt/index.html). For now, we'll just stick to the default:
|
||||
integers aren't very complicated to print.
|
||||
When you just use the curly braces, Rust will attempt to display the value in a
|
||||
meaningful way by checking out its type. If you want to specify the format in a
|
||||
more detailed manner, there are a [wide number of options available][format].
|
||||
For now, we'll just stick to the default: integers aren't very complicated to
|
||||
print.
|
||||
|
||||
[format]: ../std/fmt/index.html
|
||||
|
32
src/doc/trpl/vectors.md
Normal file
32
src/doc/trpl/vectors.md
Normal file
@ -0,0 +1,32 @@
|
||||
% Vectors
|
||||
|
||||
A *vector* is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](../std/vec/) (Where `<T>` is a [Generic](./generics.md) statement). Vectors always allocate their data on the heap. Vectors are to slices
|
||||
what `String` is to `&str`. You can create them with the `vec!` macro:
|
||||
|
||||
```{rust}
|
||||
let v = vec![1, 2, 3]; // v: Vec<i32>
|
||||
```
|
||||
|
||||
(Notice that unlike the `println!` macro we've used in the past, we use square
|
||||
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
|
||||
this is just convention.)
|
||||
|
||||
There's an alternate form of `vec!` for repeating an initial value:
|
||||
|
||||
```
|
||||
let v = vec![0; 10]; // ten zeroes
|
||||
```
|
||||
|
||||
You can get the length of, iterate over, and subscript vectors just like
|
||||
arrays. In addition, (mutable) vectors can grow automatically:
|
||||
|
||||
```{rust}
|
||||
let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
||||
|
||||
nums.push(4);
|
||||
|
||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||
```
|
||||
|
||||
Vectors have many more useful methods.
|
93
src/doc/trpl/while-loops.md
Normal file
93
src/doc/trpl/while-loops.md
Normal file
@ -0,0 +1,93 @@
|
||||
% while loops
|
||||
|
||||
Rust also has a `while` loop. It looks like this:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5; // mut x: u32
|
||||
let mut done = false; // mut done: bool
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
|
||||
println!("{}", x);
|
||||
|
||||
if x % 5 == 0 {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`while` loops are the correct choice when you’re not sure how many times
|
||||
you need to loop.
|
||||
|
||||
If you need an infinite loop, you may be tempted to write this:
|
||||
|
||||
```rust,ignore
|
||||
while true {
|
||||
```
|
||||
|
||||
However, Rust has a dedicated keyword, `loop`, to handle this case:
|
||||
|
||||
```rust,ignore
|
||||
loop {
|
||||
```
|
||||
|
||||
Rust’s control-flow analysis treats this construct differently than a `while
|
||||
true`, since we know that it will always loop. In general, the more information
|
||||
we can give to the compiler, the better it can do with safety and code
|
||||
generation, so you should always prefer `loop` when you plan to loop
|
||||
infinitely.
|
||||
|
||||
## Ending iteration early
|
||||
|
||||
Let’s take a look at that `while` loop we had earlier:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
let mut done = false;
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
|
||||
println!("{}", x);
|
||||
|
||||
if x % 5 == 0 {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We had to keep a dedicated `mut` boolean variable binding, `done`, to know
|
||||
when we should exit out of the loop. Rust has two keywords to help us with
|
||||
modifying iteration: `break` and `continue`.
|
||||
|
||||
In this case, we can write the loop in a better way with `break`:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
|
||||
loop {
|
||||
x += x - 3;
|
||||
|
||||
println!("{}", x);
|
||||
|
||||
if x % 5 == 0 { break; }
|
||||
}
|
||||
```
|
||||
|
||||
We now loop forever with `loop` and use `break` to break out early.
|
||||
|
||||
`continue` is similar, but instead of ending the loop, goes to the next
|
||||
iteration. This will only print the odd numbers:
|
||||
|
||||
```rust
|
||||
for x in 0..10 {
|
||||
if x % 2 == 0 { continue; }
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Both `continue` and `break` are valid in both `while` loops and [`for` loops][for].
|
||||
|
||||
[for]: for-loops.html
|
@ -9,6 +9,7 @@
|
||||
# except according to those terms.
|
||||
|
||||
import gdb
|
||||
import re
|
||||
|
||||
#===============================================================================
|
||||
# GDB Pretty Printing Module for Rust
|
||||
@ -299,12 +300,12 @@ def classify_struct(type):
|
||||
if fields[0].name == "RUST$ENUM$DISR":
|
||||
if field_count == 1:
|
||||
return STRUCT_KIND_CSTYLE_VARIANT
|
||||
elif fields[1].name is None:
|
||||
elif all_fields_conform_to_tuple_field_naming(fields, 1):
|
||||
return STRUCT_KIND_TUPLE_VARIANT
|
||||
else:
|
||||
return STRUCT_KIND_STRUCT_VARIANT
|
||||
|
||||
if fields[0].name is None:
|
||||
if all_fields_conform_to_tuple_field_naming(fields, 0):
|
||||
if type.tag.startswith("("):
|
||||
return STRUCT_KIND_TUPLE
|
||||
else:
|
||||
@ -325,7 +326,6 @@ def first_field(val):
|
||||
for field in val.type.fields():
|
||||
return field
|
||||
|
||||
|
||||
def get_field_at_index(val, index):
|
||||
i = 0
|
||||
for field in val.type.fields():
|
||||
@ -334,6 +334,12 @@ def get_field_at_index(val, index):
|
||||
i += 1
|
||||
return None
|
||||
|
||||
def all_fields_conform_to_tuple_field_naming(fields, start_index):
|
||||
for i in range(start_index, len(fields)):
|
||||
if (fields[i].name is None) or (re.match(r"__\d+$", fields[i].name) is None):
|
||||
return False
|
||||
return True
|
||||
|
||||
def extract_length_and_data_ptr_from_std_vec(vec_val):
|
||||
length = int(vec_val["len"])
|
||||
vec_ptr_val = vec_val["ptr"]
|
||||
|
@ -186,7 +186,8 @@ def concat_multi_lines(f):
|
||||
|
||||
firstlineno = firstlineno or lineno
|
||||
if line.endswith('\\'):
|
||||
lastline = line[:-1]
|
||||
if lastline is None:
|
||||
lastline = line[:-1]
|
||||
catenated += line[:-1]
|
||||
else:
|
||||
yield firstlineno, catenated + line
|
||||
|
@ -9,7 +9,7 @@
|
||||
# except according to those terms.
|
||||
|
||||
import lldb
|
||||
|
||||
import re
|
||||
|
||||
def print_val(val, internal_dict):
|
||||
'''Prints the given value with Rust syntax'''
|
||||
@ -61,14 +61,14 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
|
||||
# The only field of this struct is the enum discriminant
|
||||
return type_name
|
||||
|
||||
has_field_names = type_has_field_names(t)
|
||||
is_tuple_like = type_is_tuple_like(t)
|
||||
|
||||
if has_field_names:
|
||||
template = "%(type_name)s {\n%(body)s\n}"
|
||||
separator = ", \n"
|
||||
else:
|
||||
if is_tuple_like:
|
||||
template = "%(type_name)s(%(body)s)"
|
||||
separator = ", "
|
||||
else:
|
||||
template = "%(type_name)s {\n%(body)s\n}"
|
||||
separator = ", \n"
|
||||
|
||||
if type_name.startswith("("):
|
||||
# this is a tuple, so don't print the type name
|
||||
@ -76,7 +76,7 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
|
||||
|
||||
def render_child(child_index):
|
||||
this = ""
|
||||
if has_field_names:
|
||||
if not is_tuple_like:
|
||||
field_name = t.GetFieldAtIndex(child_index).GetName()
|
||||
this += field_name + ": "
|
||||
|
||||
@ -233,13 +233,15 @@ def extract_type_name(qualified_type_name):
|
||||
return qualified_type_name[index + 2:]
|
||||
|
||||
|
||||
def type_has_field_names(ty):
|
||||
def type_is_tuple_like(ty):
|
||||
'''Returns true of this is a type with field names (struct, struct-like enum variant)'''
|
||||
# This may also be an enum variant where the first field doesn't have a name but the rest has
|
||||
if ty.GetNumberOfFields() > 1:
|
||||
return ty.GetFieldAtIndex(1).GetName() is not None
|
||||
else:
|
||||
return ty.GetFieldAtIndex(0).GetName() is not None
|
||||
for field in ty.fields:
|
||||
if field.GetName() == "RUST$ENUM$DISR":
|
||||
# Ignore the enum discriminant field if there is one.
|
||||
continue
|
||||
if (field.GetName() is None) or (re.match(r"__\d+$", field.GetName()) is None):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_vec_slice(val):
|
||||
|
@ -1,615 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
|
||||
msg() {
|
||||
echo "rustup: $1"
|
||||
}
|
||||
|
||||
step_msg() {
|
||||
msg
|
||||
msg "$1"
|
||||
msg
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "rustup: WARNING: $1"
|
||||
}
|
||||
|
||||
err() {
|
||||
echo "rustup: error: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_ok() {
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
err "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
putvar() {
|
||||
local T
|
||||
eval T=\$$1
|
||||
eval TLEN=\${#$1}
|
||||
if [ $TLEN -gt 35 ]
|
||||
then
|
||||
printf "rustup: %-20s := %.35s ...\n" $1 "$T"
|
||||
else
|
||||
printf "rustup: %-20s := %s %s\n" $1 "$T" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
probe() {
|
||||
local V=$1
|
||||
shift
|
||||
local P
|
||||
local T
|
||||
for P
|
||||
do
|
||||
T=$(which $P 2>&1)
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
VER0=$($P --version 2>/dev/null | head -1 \
|
||||
| sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' )
|
||||
if [ $? -eq 0 -a "x${VER0}" != "x" ]
|
||||
then
|
||||
VER="($VER0)"
|
||||
else
|
||||
VER=""
|
||||
fi
|
||||
break
|
||||
else
|
||||
VER=""
|
||||
T=""
|
||||
fi
|
||||
done
|
||||
eval $V=\$T
|
||||
putvar $V "$VER"
|
||||
}
|
||||
|
||||
probe_need() {
|
||||
local V=$1
|
||||
probe $*
|
||||
eval VV=\$$V
|
||||
if [ -z "$VV" ]
|
||||
then
|
||||
err "needed, but unable to find any of: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
valopt() {
|
||||
VAL_OPTIONS="$VAL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
local DEFAULT=$2
|
||||
shift
|
||||
shift
|
||||
local DOC="$*"
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
|
||||
local V="CFG_${UOP}"
|
||||
eval $V="$DEFAULT"
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if echo "$arg" | grep -q -- "--$OP="
|
||||
then
|
||||
val=$(echo "$arg" | cut -f2 -d=)
|
||||
eval $V=$val
|
||||
fi
|
||||
done
|
||||
putvar $V
|
||||
else
|
||||
if [ -z "$DEFAULT" ]
|
||||
then
|
||||
DEFAULT="<none>"
|
||||
fi
|
||||
OP="${OP}=[${DEFAULT}]"
|
||||
printf " --%-30s %s\n" "$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
opt() {
|
||||
BOOL_OPTIONS="$BOOL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
local DEFAULT=$2
|
||||
shift
|
||||
shift
|
||||
local DOC="$*"
|
||||
local FLAG=""
|
||||
|
||||
if [ $DEFAULT -eq 0 ]
|
||||
then
|
||||
FLAG="enable"
|
||||
else
|
||||
FLAG="disable"
|
||||
DOC="don't $DOC"
|
||||
fi
|
||||
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if [ "$arg" = "--${FLAG}-${OP}" ]
|
||||
then
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
|
||||
local V="CFG_${FLAG}_${OP}"
|
||||
eval $V=1
|
||||
putvar $V
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ ! -z "$META" ]
|
||||
then
|
||||
OP="$OP=<$META>"
|
||||
fi
|
||||
printf " --%-30s %s\n" "$FLAG-$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
flag() {
|
||||
BOOL_OPTIONS="$BOOL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
shift
|
||||
local DOC="$*"
|
||||
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if [ "$arg" = "--${OP}" ]
|
||||
then
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
local V="CFG_${OP}"
|
||||
eval $V=1
|
||||
putvar $V
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ ! -z "$META" ]
|
||||
then
|
||||
OP="$OP=<$META>"
|
||||
fi
|
||||
printf " --%-30s %s\n" "$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_opt() {
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
isArgValid=0
|
||||
for option in $BOOL_OPTIONS
|
||||
do
|
||||
if test --disable-$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
if test --enable-$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
if test --$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
done
|
||||
for option in $VAL_OPTIONS
|
||||
do
|
||||
if echo "$arg" | grep -q -- "--$option="
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
done
|
||||
if [ "$arg" = "--help" ]
|
||||
then
|
||||
echo
|
||||
echo "No more help available for Configure options,"
|
||||
echo "check the Wiki or join our IRC channel"
|
||||
break
|
||||
else
|
||||
if test $isArgValid -eq 0
|
||||
then
|
||||
err "Option '$arg' is not recognized"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
create_tmp_dir() {
|
||||
local TMP_DIR=`pwd`/rustup-tmp-install
|
||||
|
||||
rm -Rf "${TMP_DIR}"
|
||||
need_ok "failed to remove temporary installation directory"
|
||||
|
||||
mkdir -p "${TMP_DIR}"
|
||||
need_ok "failed to create create temporary installation directory"
|
||||
|
||||
echo $TMP_DIR
|
||||
}
|
||||
|
||||
# Make `tr` locale independent
|
||||
LC_CTYPE=C
|
||||
|
||||
probe_need CFG_CURL curl
|
||||
probe_need CFG_TAR tar
|
||||
probe_need CFG_FILE file
|
||||
|
||||
probe CFG_SHA256SUM sha256sum
|
||||
probe CFG_SHASUM shasum
|
||||
|
||||
if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then
|
||||
err "unable to find either sha256sum or shasum"
|
||||
fi
|
||||
|
||||
calculate_hash() {
|
||||
if [ -n "$CFG_SHA256SUM" ]; then
|
||||
${CFG_SHA256SUM} $@
|
||||
else
|
||||
${CFG_SHASUM} -a 256 $@
|
||||
fi
|
||||
}
|
||||
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
|
||||
CFG_SELF="$0"
|
||||
CFG_ARGS="$@"
|
||||
|
||||
HELP=0
|
||||
if [ "$1" = "--help" ]
|
||||
then
|
||||
HELP=1
|
||||
shift
|
||||
echo
|
||||
echo "Usage: $CFG_SELF [options]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo
|
||||
else
|
||||
step_msg "processing $CFG_SELF args"
|
||||
fi
|
||||
|
||||
OPTIONS=""
|
||||
BOOL_OPTIONS=""
|
||||
VAL_OPTIONS=""
|
||||
|
||||
flag uninstall "only uninstall from the installation prefix"
|
||||
valopt prefix "" "set installation prefix"
|
||||
valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly"
|
||||
valopt channel "beta" "use the selected release channel [beta]"
|
||||
flag save "save the downloaded nightlies to ~/.rustup"
|
||||
|
||||
if [ $HELP -eq 1 ]
|
||||
then
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
step_msg "validating $CFG_SELF args"
|
||||
validate_opt
|
||||
|
||||
|
||||
# Platform detection copied from `configure`
|
||||
|
||||
CFG_OSTYPE=$(uname -s)
|
||||
CFG_CPUTYPE=$(uname -m)
|
||||
|
||||
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
|
||||
then
|
||||
# Darwin's `uname -m` lies and always returns i386. We have to use sysctl
|
||||
# instead.
|
||||
if sysctl hw.optional.x86_64 | grep -q ': 1'
|
||||
then
|
||||
CFG_CPUTYPE=x86_64
|
||||
fi
|
||||
fi
|
||||
|
||||
# The goal here is to come up with the same triple as LLVM would,
|
||||
# at least for the subset of platforms we're willing to target.
|
||||
|
||||
case $CFG_OSTYPE in
|
||||
|
||||
Linux)
|
||||
CFG_OSTYPE=unknown-linux-gnu
|
||||
;;
|
||||
|
||||
FreeBSD)
|
||||
CFG_OSTYPE=unknown-freebsd
|
||||
;;
|
||||
|
||||
Darwin)
|
||||
CFG_OSTYPE=apple-darwin
|
||||
;;
|
||||
|
||||
MINGW32*)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
;;
|
||||
# Thad's Cygwin identifiers below
|
||||
|
||||
# Vista 32 bit
|
||||
CYGWIN_NT-6.0)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
CFG_CPUTYPE=i686
|
||||
;;
|
||||
|
||||
# Vista 64 bit
|
||||
CYGWIN_NT-6.0-WOW64)
|
||||
CFG_OSTYPE=w64-mingw32
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
# Win 7 32 bit
|
||||
CYGWIN_NT-6.1)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
CFG_CPUTYPE=i686
|
||||
;;
|
||||
|
||||
# Win 7 64 bit
|
||||
CYGWIN_NT-6.1-WOW64)
|
||||
CFG_OSTYPE=w64-mingw32
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
# We do not detect other OS such as XP/2003 using 64 bit using uname.
|
||||
# If we want to in the future, we will need to use Cygwin
|
||||
# Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative.
|
||||
*)
|
||||
err "unknown OS type: $CFG_OSTYPE"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
case $CFG_CPUTYPE in
|
||||
|
||||
i386 | i486 | i686 | i786 | x86)
|
||||
CFG_CPUTYPE=i686
|
||||
;;
|
||||
|
||||
xscale | arm)
|
||||
CFG_CPUTYPE=arm
|
||||
;;
|
||||
|
||||
x86_64 | x86-64 | x64 | amd64)
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
*)
|
||||
err "unknown CPU type: $CFG_CPUTYPE"
|
||||
esac
|
||||
|
||||
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
|
||||
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
|
||||
then
|
||||
"${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64"
|
||||
if [ $? != 0 ]; then
|
||||
CFG_CPUTYPE=i686
|
||||
fi
|
||||
fi
|
||||
|
||||
HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}"
|
||||
|
||||
# Is this a triple we have nightlies for?
|
||||
case $HOST_TRIPLE in
|
||||
|
||||
x86_64-unknown-linux-gnu)
|
||||
;;
|
||||
|
||||
i686-unknown-linux-gnu)
|
||||
;;
|
||||
|
||||
x86_64-apple-darwin)
|
||||
;;
|
||||
|
||||
i686-apple-darwin)
|
||||
;;
|
||||
|
||||
*)
|
||||
err "rustup.sh doesn't work for host $HOST_TRIPLE"
|
||||
|
||||
esac
|
||||
|
||||
msg "host triple: ${HOST_TRIPLE}"
|
||||
|
||||
CFG_INSTALL_FLAGS=""
|
||||
if [ -n "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --uninstall"
|
||||
fi
|
||||
|
||||
if [ -n "${CFG_PREFIX}" ]
|
||||
then
|
||||
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --prefix=${CFG_PREFIX}"
|
||||
fi
|
||||
|
||||
CFG_TMP_DIR=$(mktemp -d 2>/dev/null \
|
||||
|| mktemp -d -t 'rustup-tmp-install' 2>/dev/null \
|
||||
|| create_tmp_dir)
|
||||
|
||||
# If we're saving nightlies and we didn't specify which one, grab the latest
|
||||
# version from the perspective of the server. Buildbot has typically finished
|
||||
# building and uploading by ~8UTC, but we want to include a little buffer.
|
||||
#
|
||||
# FIXME It would be better to use the known most recent nightly that has been
|
||||
# built. This is waiting on a change to have buildbot publish metadata that
|
||||
# can be queried.
|
||||
if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ];
|
||||
then
|
||||
CFG_DATE=`TZ=Etc/UTC+9 date "+%Y-%m-%d"`
|
||||
fi
|
||||
|
||||
RUST_URL="https://static.rust-lang.org/dist"
|
||||
case "$CFG_CHANNEL" in
|
||||
nightly)
|
||||
# add a date suffix if we want a particular nightly.
|
||||
if [ -n "${CFG_DATE}" ];
|
||||
then
|
||||
RUST_URL="${RUST_URL}/${CFG_DATE}"
|
||||
fi
|
||||
|
||||
RUST_PACKAGE_NAME=rust-nightly
|
||||
;;
|
||||
beta)
|
||||
RUST_PACKAGE_NAME=rust-1.0.0-beta
|
||||
;;
|
||||
*)
|
||||
err "Currently 'beta' and 'nightly' are the only supported channels"
|
||||
esac
|
||||
|
||||
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
|
||||
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
|
||||
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
|
||||
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
|
||||
|
||||
download_hash() {
|
||||
msg "Downloading ${remote_sha256}"
|
||||
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
|
||||
if [ -n "${CFG_SAVE}" ]; then
|
||||
echo "${remote_sha256}" > "${local_sha_file}"
|
||||
fi
|
||||
if [ "$?" -ne 0 ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "Failed to download ${remote_url}"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_hash() {
|
||||
remote_sha256="$1"
|
||||
local_file="$2"
|
||||
local_sha_file="${local_file}.sha256"
|
||||
|
||||
if [ -n "${CFG_SAVE}" ]; then
|
||||
if [ -f "${local_sha_file}" ]; then
|
||||
msg "Local ${local_sha_file} exists, treating as remote hash"
|
||||
remote_sha256=`cat "${local_sha_file}"`
|
||||
else
|
||||
download_hash
|
||||
fi
|
||||
else
|
||||
download_hash
|
||||
fi
|
||||
|
||||
msg "Verifying hash"
|
||||
local_sha256=$(calculate_hash "${local_file}")
|
||||
if [ "$?" -ne 0 ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "Failed to compute hash for ${local_tarball}"
|
||||
fi
|
||||
|
||||
# We only need the sha, not the filenames
|
||||
remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '`
|
||||
local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '`
|
||||
|
||||
if [ "${remote_sha256}" != "${local_sha256}" ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
errmsg="invalid sha256.\n"
|
||||
errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n"
|
||||
errmsg="$errmsg ${local_sha256}\t${local_tarball}"
|
||||
err "$errmsg"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetch the package. Optionally caches the tarballs.
|
||||
download_package() {
|
||||
remote_tarball="$1"
|
||||
local_tarball="$2"
|
||||
remote_sha256="${remote_tarball}.sha256"
|
||||
|
||||
# Check if we've already downloaded this file.
|
||||
if [ -e "${local_tarball}.tmp" ]; then
|
||||
msg "Resuming ${remote_tarball} to ${local_tarball}"
|
||||
|
||||
"${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to download installer"
|
||||
fi
|
||||
|
||||
mv "${local_tarball}.tmp" "${local_tarball}"
|
||||
elif [ ! -e "${local_tarball}" ]; then
|
||||
msg "Downloading ${remote_tarball} to ${local_tarball}"
|
||||
|
||||
"${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to download installer"
|
||||
fi
|
||||
|
||||
mv "${local_tarball}.tmp" "${local_tarball}"
|
||||
fi
|
||||
|
||||
verify_hash "${remote_sha256}" "${local_tarball}"
|
||||
}
|
||||
|
||||
# Wrap all the commands needed to install a package.
|
||||
install_package() {
|
||||
local_tarball="$1"
|
||||
install_script="$2"
|
||||
|
||||
msg "Extracting ${local_tarball}"
|
||||
(cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}")
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to unpack installer"
|
||||
fi
|
||||
|
||||
sh "${install_script}" "${CFG_INSTALL_FLAGS}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to install Rust"
|
||||
fi
|
||||
}
|
||||
|
||||
# It's possible that curl could be interrupted partway though downloading
|
||||
# `rustup.sh`, truncating the file. This could be especially bad if we were in
|
||||
# the middle of a line that would run "rm -rf ". To protect against this, we
|
||||
# wrap up the `rustup.sh` destructive functionality in this helper function,
|
||||
# which we call as the last thing we do. This means we will not do anything
|
||||
# unless we have the entire file downloaded.
|
||||
install_packages() {
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
need_ok "failed to remove temporary installation directory"
|
||||
|
||||
mkdir -p "${CFG_TMP_DIR}"
|
||||
need_ok "failed to create create temporary installation directory"
|
||||
|
||||
# If we're saving our nightlies, put them in $HOME/.rustup.
|
||||
if [ -n "${CFG_SAVE}" ]
|
||||
then
|
||||
RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}"
|
||||
else
|
||||
RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}"
|
||||
fi
|
||||
|
||||
mkdir -p "${RUST_DOWNLOAD_DIR}"
|
||||
need_ok "failed to create create download directory"
|
||||
|
||||
RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}"
|
||||
|
||||
download_package \
|
||||
"${RUST_URL}/${RUST_TARBALL_NAME}" \
|
||||
"${RUST_LOCAL_TARBALL}"
|
||||
|
||||
install_package \
|
||||
"${RUST_LOCAL_TARBALL}" \
|
||||
"${RUST_LOCAL_INSTALL_SCRIPT}"
|
||||
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
need_ok "couldn't rm temporary installation directory"
|
||||
}
|
||||
|
||||
install_packages
|
Binary file not shown.
@ -12,8 +12,11 @@
|
||||
|
||||
# This script uses the following Unicode tables:
|
||||
# - DerivedCoreProperties.txt
|
||||
# - DerivedNormalizationProps.txt
|
||||
# - EastAsianWidth.txt
|
||||
# - auxiliary/GraphemeBreakProperty.txt
|
||||
# - PropList.txt
|
||||
# - ReadMe.txt
|
||||
# - Scripts.txt
|
||||
# - UnicodeData.txt
|
||||
#
|
||||
@ -51,41 +54,20 @@ expanded_categories = {
|
||||
'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'],
|
||||
}
|
||||
|
||||
|
||||
# Grapheme cluster data
|
||||
# taken from UAX29, http://www.unicode.org/reports/tr29/
|
||||
# these code points are excluded from the Control category
|
||||
# NOTE: CR and LF are also technically excluded, but for
|
||||
# the sake of convenience we leave them in the Control group
|
||||
# and manually check them in the appropriate place. This is
|
||||
# still compliant with the implementation requirements.
|
||||
grapheme_control_exceptions = set([0x200c, 0x200d])
|
||||
|
||||
# the Regional_Indicator category
|
||||
grapheme_regional_indicator = [(0x1f1e6, 0x1f1ff)]
|
||||
|
||||
# "The following ... are specifically excluded" from the SpacingMark category
|
||||
# http://www.unicode.org/reports/tr29/#SpacingMark
|
||||
grapheme_spacingmark_exceptions = [(0x102b, 0x102c), (0x1038, 0x1038),
|
||||
(0x1062, 0x1064), (0x1067, 0x106d), (0x1083, 0x1083), (0x1087, 0x108c),
|
||||
(0x108f, 0x108f), (0x109a, 0x109c), (0x19b0, 0x19b4), (0x19b8, 0x19b9),
|
||||
(0x19bb, 0x19c0), (0x19c8, 0x19c9), (0x1a61, 0x1a61), (0x1a63, 0x1a64),
|
||||
(0xaa7b, 0xaa7b), (0xaa7d, 0xaa7d)]
|
||||
|
||||
# these are included in the SpacingMark category
|
||||
grapheme_spacingmark_extra = set([0xe33, 0xeb3])
|
||||
# these are the surrogate codepoints, which are not valid rust characters
|
||||
surrogate_codepoints = (0xd800, 0xdfff)
|
||||
|
||||
def fetch(f):
|
||||
if not os.path.exists(f):
|
||||
if not os.path.exists(os.path.basename(f)):
|
||||
os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s"
|
||||
% f)
|
||||
|
||||
if not os.path.exists(f):
|
||||
if not os.path.exists(os.path.basename(f)):
|
||||
sys.stderr.write("cannot load %s" % f)
|
||||
exit(1)
|
||||
|
||||
def is_surrogate(n):
|
||||
return 0xD800 <= n <= 0xDFFF
|
||||
return surrogate_codepoints[0] <= n <= surrogate_codepoints[1]
|
||||
|
||||
def load_unicode_data(f):
|
||||
fetch(f)
|
||||
@ -228,7 +210,7 @@ def load_properties(f, interestingprops):
|
||||
re1 = re.compile("^([0-9A-F]+) +; (\w+)")
|
||||
re2 = re.compile("^([0-9A-F]+)\.\.([0-9A-F]+) +; (\w+)")
|
||||
|
||||
for line in fileinput.input(f):
|
||||
for line in fileinput.input(os.path.basename(f)):
|
||||
prop = None
|
||||
d_lo = 0
|
||||
d_hi = 0
|
||||
@ -323,33 +305,13 @@ def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True,
|
||||
format_table_content(f, data, 8)
|
||||
f.write("\n ];\n\n")
|
||||
|
||||
def emit_property_module(f, mod, tbl, emit_fn):
|
||||
def emit_property_module(f, mod, tbl, emit):
|
||||
f.write("pub mod %s {\n" % mod)
|
||||
keys = tbl.keys()
|
||||
keys.sort()
|
||||
for cat in keys:
|
||||
for cat in sorted(emit):
|
||||
emit_table(f, "%s_table" % cat, tbl[cat])
|
||||
if cat in emit_fn:
|
||||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" super::bsearch_range_table(c, %s_table)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
f.write("}\n\n")
|
||||
|
||||
def emit_regex_module(f, cats, w_data):
|
||||
f.write("pub mod regex {\n")
|
||||
regex_class = "&'static [(char, char)]"
|
||||
class_table = "&'static [(&'static str, %s)]" % regex_class
|
||||
|
||||
emit_table(f, "UNICODE_CLASSES", cats, class_table,
|
||||
pfun=lambda x: "(\"%s\",super::%s::%s_table)" % (x[0], x[1], x[0]))
|
||||
|
||||
f.write(" pub const PERLD: %s = super::general_category::Nd_table;\n\n"
|
||||
% regex_class)
|
||||
f.write(" pub const PERLS: %s = super::property::White_Space_table;\n\n"
|
||||
% regex_class)
|
||||
|
||||
emit_table(f, "PERLW", w_data, regex_class)
|
||||
|
||||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" super::bsearch_range_table(c, %s_table)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
f.write("}\n\n")
|
||||
|
||||
def emit_conversions_module(f, lowerupper, upperlower):
|
||||
@ -623,44 +585,21 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
|
||||
(canon_decomp, compat_decomp, gencats, combines,
|
||||
lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
|
||||
want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"]
|
||||
other_derived = ["Default_Ignorable_Code_Point", "Grapheme_Extend"]
|
||||
derived = load_properties("DerivedCoreProperties.txt", want_derived + other_derived)
|
||||
derived = load_properties("DerivedCoreProperties.txt", want_derived)
|
||||
scripts = load_properties("Scripts.txt", [])
|
||||
props = load_properties("PropList.txt",
|
||||
["White_Space", "Join_Control", "Noncharacter_Code_Point"])
|
||||
norm_props = load_properties("DerivedNormalizationProps.txt",
|
||||
["Full_Composition_Exclusion"])
|
||||
|
||||
# grapheme cluster category from DerivedCoreProperties
|
||||
# the rest are defined below
|
||||
grapheme_cats = {}
|
||||
grapheme_cats["Extend"] = derived["Grapheme_Extend"]
|
||||
del(derived["Grapheme_Extend"])
|
||||
|
||||
# bsearch_range_table is used in all the property modules below
|
||||
emit_bsearch_range_table(rf)
|
||||
|
||||
# all of these categories will also be available as \p{} in libregex
|
||||
allcats = []
|
||||
# category tables
|
||||
for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \
|
||||
("derived_property", derived, want_derived), \
|
||||
("script", scripts, []), \
|
||||
("property", props, ["White_Space"]):
|
||||
emit_property_module(rf, name, cat, pfuns)
|
||||
allcats.extend(map(lambda x: (x, name), cat))
|
||||
allcats.sort(key=lambda c: c[0])
|
||||
|
||||
# the \w regex corresponds to Alphabetic + Mark + Decimal_Number +
|
||||
# Connector_Punctuation + Join-Control according to UTS#18
|
||||
# http://www.unicode.org/reports/tr18/#Compatibility_Properties
|
||||
perl_words = []
|
||||
for cat in derived["Alphabetic"], gencats["M"], gencats["Nd"], \
|
||||
gencats["Pc"], props["Join_Control"]:
|
||||
perl_words.extend(ungroup_cat(cat))
|
||||
perl_words = group_cat(perl_words)
|
||||
|
||||
# emit lookup tables for \p{}, along with \d, \w, and \s for libregex
|
||||
emit_regex_module(rf, allcats, perl_words)
|
||||
|
||||
# normalizations and conversions module
|
||||
emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props)
|
||||
@ -691,34 +630,24 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
|
||||
|
||||
### grapheme cluster module
|
||||
# from http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Break_Property_Values
|
||||
# Hangul syllable categories
|
||||
want_hangul = ["L", "V", "T", "LV", "LVT"]
|
||||
grapheme_cats.update(load_properties("HangulSyllableType.txt", want_hangul))
|
||||
grapheme_cats = load_properties("auxiliary/GraphemeBreakProperty.txt", [])
|
||||
|
||||
# Control
|
||||
# Note 1:
|
||||
# This category also includes Cs (surrogate codepoints), but Rust's `char`s are
|
||||
# Unicode Scalar Values only, and surrogates are thus invalid `char`s.
|
||||
grapheme_cats["Control"] = set()
|
||||
for cat in ["Zl", "Zp", "Cc", "Cf"]:
|
||||
grapheme_cats["Control"] |= set(ungroup_cat(gencats[cat]))
|
||||
# Thus, we have to remove Cs from the Control category
|
||||
# Note 2:
|
||||
# 0x0a and 0x0d (CR and LF) are not in the Control category for Graphemes.
|
||||
# However, the Graphemes iterator treats these as a special case, so they
|
||||
# should be included in grapheme_cats["Control"] for our implementation.
|
||||
grapheme_cats["Control"] = group_cat(list(
|
||||
grapheme_cats["Control"]
|
||||
- grapheme_control_exceptions
|
||||
| (set(ungroup_cat(gencats["Cn"]))
|
||||
& set(ungroup_cat(derived["Default_Ignorable_Code_Point"])))))
|
||||
|
||||
# Regional Indicator
|
||||
grapheme_cats["RegionalIndicator"] = grapheme_regional_indicator
|
||||
|
||||
# Prepend - "Currently there are no characters with this value"
|
||||
# (from UAX#29, Unicode 7.0)
|
||||
|
||||
# SpacingMark
|
||||
grapheme_cats["SpacingMark"] = group_cat(list(
|
||||
set(ungroup_cat(gencats["Mc"]))
|
||||
- set(ungroup_cat(grapheme_cats["Extend"]))
|
||||
| grapheme_spacingmark_extra
|
||||
- set(ungroup_cat(grapheme_spacingmark_exceptions))))
|
||||
(set(ungroup_cat(grapheme_cats["Control"]))
|
||||
| set(ungroup_cat(grapheme_cats["CR"]))
|
||||
| set(ungroup_cat(grapheme_cats["LF"])))
|
||||
- set(ungroup_cat([surrogate_codepoints]))))
|
||||
del(grapheme_cats["CR"])
|
||||
del(grapheme_cats["LF"])
|
||||
|
||||
grapheme_table = []
|
||||
for cat in grapheme_cats:
|
||||
|
@ -1 +1 @@
|
||||
0.12.0-7693-g9854143cba679834bc4ef932858cd5303f015a0e
|
||||
0.12.0-8312-g5241bf9c34d156ea6064367a33cbd7222eeb5789
|
||||
|
@ -77,7 +77,6 @@ use core::atomic;
|
||||
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
|
||||
use core::fmt;
|
||||
use core::cmp::Ordering;
|
||||
use core::default::Default;
|
||||
use core::mem::{min_align_of, size_of};
|
||||
use core::mem;
|
||||
use core::nonzero::NonZero;
|
||||
@ -103,7 +102,7 @@ use heap::deallocate;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let numbers: Vec<_> = (0..100u32).map(|i| i as f32).collect();
|
||||
/// let numbers: Vec<_> = (0..100u32).collect();
|
||||
/// let shared_numbers = Arc::new(numbers);
|
||||
///
|
||||
/// for _ in 0..10 {
|
||||
@ -243,10 +242,9 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
|
||||
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
|
||||
|
||||
|
||||
/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
|
||||
/// Returns a mutable reference to the contained value if the `Arc<T>` is unique.
|
||||
///
|
||||
/// The access is granted only if this is the only reference to the object.
|
||||
/// Otherwise, `None` is returned.
|
||||
/// Returns `None` if the `Arc<T>` is not unique.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -254,16 +252,19 @@ pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst
|
||||
/// # #![feature(alloc)]
|
||||
/// extern crate alloc;
|
||||
/// # fn main() {
|
||||
/// use alloc::arc;
|
||||
/// use alloc::arc::{Arc, get_mut};
|
||||
///
|
||||
/// let mut four = arc::Arc::new(4);
|
||||
/// let mut x = Arc::new(3);
|
||||
/// *get_mut(&mut x).unwrap() = 4;
|
||||
/// assert_eq!(*x, 4);
|
||||
///
|
||||
/// arc::unique(&mut four).map(|num| *num = 5);
|
||||
/// let _y = x.clone();
|
||||
/// assert!(get_mut(&mut x).is_none());
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
pub fn get_mut<T>(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
if strong_count(this) == 1 && weak_count(this) == 0 {
|
||||
// This unsafety is ok because we're guaranteed that the pointer
|
||||
// returned is the *only* pointer that will ever be returned to T. Our
|
||||
@ -272,7 +273,7 @@ pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
// reference to the inner data.
|
||||
let inner = unsafe { &mut **this._ptr };
|
||||
Some(&mut inner.data)
|
||||
}else {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -347,7 +348,7 @@ impl<T: Clone> Arc<T> {
|
||||
self.inner().weak.load(SeqCst) != 1 {
|
||||
*self = Arc::new((**self).clone())
|
||||
}
|
||||
// As with `unique()`, the unsafety is ok because our reference was
|
||||
// As with `get_mut()`, the unsafety is ok because our reference was
|
||||
// either unique to begin with, or became one upon cloning the contents.
|
||||
let inner = unsafe { &mut **self._ptr };
|
||||
&mut inner.data
|
||||
@ -446,7 +447,7 @@ impl<T> Weak<T> {
|
||||
/// ```
|
||||
pub fn upgrade(&self) -> Option<Arc<T>> {
|
||||
// We use a CAS loop to increment the strong count instead of a
|
||||
// fetch_add because once the count hits 0 is must never be above 0.
|
||||
// fetch_add because once the count hits 0 it must never be above 0.
|
||||
let inner = self.inner();
|
||||
loop {
|
||||
let n = inner.strong.load(SeqCst);
|
||||
@ -666,6 +667,13 @@ impl<T: fmt::Debug> fmt::Debug for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> fmt::Pointer for Arc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Pointer::fmt(&*self._ptr, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default + Sync + Send> Default for Arc<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -691,7 +699,7 @@ mod tests {
|
||||
use std::sync::atomic::Ordering::{Acquire, SeqCst};
|
||||
use std::thread;
|
||||
use std::vec::Vec;
|
||||
use super::{Arc, Weak, weak_count, strong_count, unique};
|
||||
use super::{Arc, Weak, get_mut, weak_count, strong_count};
|
||||
use std::sync::Mutex;
|
||||
|
||||
struct Canary(*mut atomic::AtomicUsize);
|
||||
@ -728,18 +736,16 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arc_unique() {
|
||||
let mut x = Arc::new(10);
|
||||
assert!(unique(&mut x).is_some());
|
||||
{
|
||||
let y = x.clone();
|
||||
assert!(unique(&mut x).is_none());
|
||||
}
|
||||
{
|
||||
let z = x.downgrade();
|
||||
assert!(unique(&mut x).is_none());
|
||||
}
|
||||
assert!(unique(&mut x).is_some());
|
||||
fn test_arc_get_mut() {
|
||||
let mut x = Arc::new(3);
|
||||
*get_mut(&mut x).unwrap() = 4;
|
||||
assert_eq!(*x, 4);
|
||||
let y = x.clone();
|
||||
assert!(get_mut(&mut x).is_none());
|
||||
drop(y);
|
||||
assert!(get_mut(&mut x).is_some());
|
||||
let _w = x.downgrade();
|
||||
assert!(get_mut(&mut x).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -10,14 +10,9 @@
|
||||
|
||||
//! A pointer type for heap allocation.
|
||||
//!
|
||||
//! `Box<T>`, casually referred to as a 'box', provides the simplest form of
|
||||
//! heap allocation in Rust. Boxes provide ownership for this allocation, and
|
||||
//! drop their contents when they go out of scope.
|
||||
//!
|
||||
//! Boxes are useful in two situations: recursive data structures, and
|
||||
//! occasionally when returning data. [The Pointer chapter of the
|
||||
//! Book](../../../book/pointers.html#best-practices-1) explains these cases in
|
||||
//! detail.
|
||||
//! `Box<T>`, casually referred to as a 'box', provides the simplest form of heap allocation in
|
||||
//! Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of
|
||||
//! scope.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
@ -43,6 +38,16 @@
|
||||
//! ```
|
||||
//!
|
||||
//! This will print `Cons(1, Box(Cons(2, Box(Nil))))`.
|
||||
//!
|
||||
//! Recursive structures must be boxed, because if the definition of `Cons` looked like this:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! Cons(T, List<T>),
|
||||
//! ```
|
||||
//!
|
||||
//! It wouldn't work. This is because the size of a `List` depends on how many elements are in the
|
||||
//! list, and so we don't know how much memory to allocate for a `Cons`. By introducing a `Box`,
|
||||
//! which has a defined size, we know how big `Cons` needs to be.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
@ -50,7 +55,6 @@ use core::prelude::*;
|
||||
|
||||
use core::any::Any;
|
||||
use core::cmp::Ordering;
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::mem;
|
||||
@ -275,6 +279,16 @@ impl<T: fmt::Debug + ?Sized> fmt::Debug for Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> fmt::Pointer for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// It's not possible to extract the inner Uniq directly from the Box,
|
||||
// instead we cast it to a *const which aliases the Unique
|
||||
let ptr: *const T = &**self;
|
||||
fmt::Pointer::fmt(&ptr, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for Box<T> {
|
||||
type Target = T;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user