mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 10:55:14 +00:00
Fix the relative path issue by including the files using include_bytes!
This commit is contained in:
commit
f6e9240a99
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,6 +19,7 @@
|
||||
*.exe
|
||||
*.fn
|
||||
*.html
|
||||
*.kdev4
|
||||
*.ky
|
||||
*.ll
|
||||
*.llvm
|
||||
|
17
.mailmap
17
.mailmap
@ -8,12 +8,13 @@
|
||||
Aaron Todd <github@opprobrio.us>
|
||||
Abhishek Chanda <abhishek.becs@gmail.com> Abhishek Chanda <abhishek@cloudscaling.com>
|
||||
Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com>
|
||||
Aydin Kim <ladinjin@hanmail.net> aydin.kim <aydin.kim@samsung.com>
|
||||
Alex Lyon <arcterus@mail.com> <Arcterus@mail.com>
|
||||
Alex Rønne Petersen <alex@lycus.org>
|
||||
Andreas Gal <gal@mozilla.com> <andreas.gal@gmail.com>
|
||||
Andrew Poelstra <asp11@sfu.ca> <apoelstra@wpsoftware.net>
|
||||
Anton Löfgren <anton.lofgren@gmail.com> <alofgren@op5.com>
|
||||
Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> <ariel.byd@gmail.com>
|
||||
Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> arielb1 <arielb1@mail.tau.ac.il> <ariel.byd@gmail.com>
|
||||
Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org>
|
||||
Ben Alpert <ben@benalpert.com> <spicyjalapeno@gmail.com>
|
||||
Benjamin Jackman <ben@jackman.biz>
|
||||
@ -38,6 +39,7 @@ Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
|
||||
Eduardo Bautista <me@eduardobautista.com> <=>
|
||||
Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com>
|
||||
Elly Fong-Jones <elly@leptoquark.net>
|
||||
Emily Dunham <edunham@mozilla.com> edunham <edunham@mozilla.com>
|
||||
Eric Holk <eric.holk@gmail.com> <eholk@mozilla.com>
|
||||
Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu>
|
||||
Eric Holmes <eric@ejholmes.net>
|
||||
@ -45,6 +47,7 @@ Eric Reed <ecreed@cs.washington.edu> <ereed@mozilla.com>
|
||||
Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org>
|
||||
Evgeny Sologubov
|
||||
Falco Hirschenberger <falco.hirschenberger@gmail.com> <hirschen@itwm.fhg.de>
|
||||
Felix S. Klock II <pnkfelix@pnkfx.org> Felix S Klock II <pnkfelix@pnkfx.org>
|
||||
Gareth Daniel Smith <garethdanielsmith@gmail.com>
|
||||
Georges Dubus <georges.dubus@gmail.com> <georges.dubus@compiletoi.net>
|
||||
Graham Fawcett <fawcett@uwindsor.ca> <graham.fawcett@gmail.com>
|
||||
@ -64,6 +67,7 @@ Jihyun Yu <jihyun@nclab.kaist.ac.kr> jihyun <jihyun@nablecomm.com>
|
||||
Jihyun Yu <jihyun@nclab.kaist.ac.kr> <yjh0502@gmail.com>
|
||||
Johann Hofmann <mail@johann-hofmann.com> Johann <git@johann-hofmann.com> Johann Hofmann <git@johann-hofmann.com>
|
||||
John Clements <clements@racket-lang.org> <clements@brinckerhoff.org>
|
||||
John Hodge <acessdev@gmail.com> John Hodge <tpg@mutabah.net>
|
||||
Jorge Aparicio <japaric@linux.com> <japaricious@gmail.com>
|
||||
Jonathan Bailey <jbailey@mozilla.com> <jbailey@jbailey-20809.local>
|
||||
Junyoung Cho <june0.cho@samsung.com>
|
||||
@ -80,20 +84,24 @@ Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
|
||||
Luke Metz <luke.metz@students.olin.edu>
|
||||
Makoto Nakashima <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
|
||||
Makoto Nakashima <makoto.nksm+github@gmail.com> gifnksm <makoto.nksm+github@gmail.com>
|
||||
Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
|
||||
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> <mmeyerho@andrew>
|
||||
Mark Sinclair <mark.edward.x@gmail.com>
|
||||
Mark Sinclair <mark.edward.x@gmail.com> =Mark Sinclair <=125axel125@gmail.com>
|
||||
Matej Lach <matej.lach@gmail.com> Matej Ľach <matej.lach@gmail.com>
|
||||
Matt Brubeck <mbrubeck@limpet.net> <mbrubeck@cs.hmc.edu>
|
||||
Matthew Auld <matthew.auld@intel.com>
|
||||
Matthew McPherrin <matthew@mcpherrin.ca> <matt@mcpherrin.ca>
|
||||
Matthijs Hofstra <thiezz@gmail.com>
|
||||
Michael Williams <m.t.williams@live.com>
|
||||
Michael Woerister <michaelwoerister@gmail> <michaelwoerister@gmail.com>
|
||||
Michael Woerister <michaelwoerister@gmail> <michaelwoerister@posteo>
|
||||
Michael Woerister <michaelwoerister@gmail> <michaelwoerister@gmail.com> <michaelwoerister@posteo> Michael Woerister <michaelwoerister@posteo>
|
||||
Neil Pankey <npankey@gmail.com> <neil@wire.im>
|
||||
Nicholas Mazzuca <npmazzuca@gmail.com> Nicholas <npmazzuca@gmail.com>
|
||||
Oliver Schneider <github6541940@oli-obk.de> <git1984941651981@oli-obk.de> <git1984941651981@oli-obk.de> Oliver 'ker' Schneider <rust19446194516@oli-obk.de>
|
||||
Ožbolt Menegatti <ozbolt.menegatti@gmail.com> gareins <ozbolt.menegatti@gmail.com>
|
||||
Paul Faria <paul_faria@ultimatesoftware.com> Paul Faria <Nashenas88@gmail.com>
|
||||
Peer Aramillo Irizar <peer.aramillo.irizar@gmail.com> parir <peer.aramillo.irizar@gmail.com>
|
||||
Peter Elmers <peter.elmers@yahoo.com> <peter.elmers@rice.edu>
|
||||
Philipp Brüschweiler <blei42@gmail.com> <blei42@gmail.com>
|
||||
Philipp Brüschweiler <blei42@gmail.com> <bruphili@student.ethz.ch>
|
||||
Pradeep Kumar <gohanpra@gmail.com>
|
||||
@ -105,6 +113,7 @@ Robert Foss <dev@robertfoss.se> robertfoss <dev@robertfoss.se>
|
||||
Robert Gawdzik <rgawdzik@hotmail.com> Robert Gawdzik ☢ <rgawdzik@hotmail.com>
|
||||
Robert Millar <robert.millar@cantab.net>
|
||||
Ryan Scheel <ryan.havvy@gmail.com>
|
||||
Sean Gillespie <sean.william.g@gmail.com> swgillespie <sean.william.g@gmail.com>
|
||||
Seonghyun Kim <sh8281.kim@samsung.com>
|
||||
Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server>
|
||||
Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
|
||||
@ -114,7 +123,9 @@ Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca> <sstewartgallus00@mylanga
|
||||
Tamir Duberstein <tamird@gmail.com> Tamir Duberstein <tamird@squareup.com>
|
||||
Tim Chevalier <chevalier@alum.wellesley.edu> <catamorphism@gmail.com>
|
||||
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
|
||||
Vadim Petrochenkov <vadim.petrochenkov@gmail.com> petrochenkov <vadim.petrochenkov@gmail.com>
|
||||
William Ting <io@williamting.com> <william.h.ting@gmail.com>
|
||||
Xuefeng Wu <benewu@gmail.com> Xuefeng Wu <xfwu@thoughtworks.com> XuefengWu <benewu@gmail.com>
|
||||
Youngsoo Son <ysson83@gmail.com> <ysoo.son@samsung.com>
|
||||
Zack Corr <zack@z0w0.me> <zackcorr95@gmail.com>
|
||||
Zack Slayton <zack.slayton@gmail.com>
|
||||
|
30
.travis.yml
30
.travis.yml
@ -1,7 +1,9 @@
|
||||
# Use something that's not 'ruby' so we don't set up things like
|
||||
# RVM/bundler/ruby and whatnot. Right now 'rust' as a language actually
|
||||
# downloads a rust/cargo snapshot, which we don't really want for building rust.
|
||||
# ccache support is disabled unless your language is a C-derivative. However
|
||||
# `language: C` unconditionally sets `CC=compiler`. If we just set it in our
|
||||
# `env` it will be overwritten by the default (gcc 4.6).
|
||||
language: c
|
||||
compiler: /usr/bin/gcc-4.7
|
||||
cache: ccache
|
||||
sudo: false
|
||||
|
||||
# The test suite is in general way too stressful for travis, especially in
|
||||
@ -9,12 +11,28 @@ sudo: false
|
||||
# back to only build the stage1 compiler and run a subset of tests, but this
|
||||
# didn't end up panning out very well.
|
||||
#
|
||||
# As a result, we're just using travis to run `make tidy` now. It'll help
|
||||
# everyone find out about their trailing spaces early on!
|
||||
# As a result, we're just using travis to run `make tidy` and *only* build
|
||||
# stage1 but *not* test it for now (a strict subset of the bootstrap). This will
|
||||
# catch "obvious" errors like style or not even compiling.
|
||||
#
|
||||
# We need gcc4.7 or higher to build LLVM, and travis (well, Ubuntu 12.04)
|
||||
# currently ships with 4.6. Gotta download our own.
|
||||
before_script:
|
||||
- ./configure --llvm-root=path/to/nowhere
|
||||
- ./configure --enable-ccache
|
||||
script:
|
||||
- make tidy
|
||||
- make rustc-stage1 -j4
|
||||
|
||||
env:
|
||||
- CXX=/usr/bin/g++-4.7
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.7
|
||||
- g++-4.7
|
||||
|
||||
# Real testing happens on http://buildbot.rust-lang.org/
|
||||
#
|
||||
|
85
AUTHORS.txt
85
AUTHORS.txt
@ -22,11 +22,13 @@ Aidan Cully <github@aidan.users.panix.com>
|
||||
Aidan Hobson Sayers <aidanhs@cantab.net>
|
||||
A.J. Gardner <mrhota@users.noreply.github.com>
|
||||
Akos Kiss <akiss@inf.u-szeged.hu>
|
||||
Akshay Chiwhane <achiwhane@gmail.com>
|
||||
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>
|
||||
Alexander Artemenko <svetlyak.40wt@gmail.com>
|
||||
Alexander Bliskovsky <alexander.bliskovsky@gmail.com>
|
||||
Alexander Campbell <alexanderhcampbell@gmail.com>
|
||||
Alexander Chernyakhovsky <achernya@mit.edu>
|
||||
@ -44,6 +46,7 @@ Alexis Beingessner <a.beingessner@gmail.com>
|
||||
Alex Lyon <arcterus@mail.com>
|
||||
Alex Quach <alex@clinkle.com>
|
||||
Alex Rønne Petersen <alex@lycus.org>
|
||||
Alex Stokes <r.alex.stokes@gmail.com>
|
||||
Alex Whitney <aw1209@ic.ac.uk>
|
||||
Alfie John <alfie@alfie.wtf>
|
||||
Alisdair Owens <awo101@zepler.net>
|
||||
@ -66,8 +69,10 @@ Andrew Barchuk <raindev@icloud.com>
|
||||
Andrew Cann <shum@canndrew.org>
|
||||
Andrew Chin <achin@eminence32.net>
|
||||
Andrew Dunham <andrew@du.nham.ca>
|
||||
Andrew Foote <afoote97@gmail.com>
|
||||
Andrew Gallant <jamslam@gmail.com>
|
||||
Andrew Hobden <andrew@hoverbear.org>
|
||||
Andrew Kensler <andrew@eastfarthing.com>
|
||||
Andrew Paseltiner <apaseltiner@gmail.com>
|
||||
Andrew Poelstra <asp11@sfu.ca>
|
||||
Andrew Seidl <dev@aas.io>
|
||||
@ -93,19 +98,21 @@ Ashok Gautham <ScriptDevil@gmail.com>
|
||||
Augusto Hack <hack.augusto@gmail.com>
|
||||
auREAX <mark@xn--hwg34fba.ws>
|
||||
Austin Bonander <austin.bonander@gmail.com>
|
||||
Austin Hellyer <hello@austinhellyer.me>
|
||||
Austin King <shout@ozten.com>
|
||||
Austin Seipp <mad.one@gmail.com>
|
||||
Avdi Grimm <avdi@avdi.org>
|
||||
awlnx <alecweber1994@gmail.com>
|
||||
Axel Viala <axel.viala@darnuria.eu>
|
||||
aydin.kim <aydin.kim@samsung.com>
|
||||
Aydin Kim <ladinjin@hanmail.net>
|
||||
bachm <Ab@vapor.com>
|
||||
Barosl Lee <vcs@barosl.com>
|
||||
bcoopers <coopersmithbrian@gmail.com>
|
||||
Ben Alpert <ben@benalpert.com>
|
||||
benaryorg <binary@benary.org>
|
||||
Ben Ashford <ben@bcash.org>
|
||||
Ben Blum <bblum@andrew.cmu.edu>
|
||||
ben fleis <ben.fleis@gmail.com>
|
||||
Ben Foppa <benjamin.foppa@gmail.com>
|
||||
Ben Gamari <bgamari.foss@gmail.com>
|
||||
Ben Gesoff <ben.gesoff@gmail.com>
|
||||
@ -128,6 +135,7 @@ Birunthan Mohanathas <birunthan@mohanathas.com>
|
||||
Björn Steinbrink <bsteinbr@gmail.com>
|
||||
blake2-ppc <ulrik.sverdrup@gmail.com>
|
||||
bluss <bluss>
|
||||
bluss <bluss@users.noreply.github.com>
|
||||
Boris Egorov <egorov@linux.com>
|
||||
bors <bors@rust-lang.org>
|
||||
Bouke van der Bijl <boukevanderbijl@gmail.com>
|
||||
@ -149,6 +157,7 @@ Brian J Brennan <brianloveswords@gmail.com>
|
||||
Brian J. Burg <burg@cs.washington.edu>
|
||||
Brian Koropoff <bkoropoff@gmail.com>
|
||||
Brian Leibig <brian@brianleibig.com>
|
||||
Brian Quinlan <brian@sweetapp.com>
|
||||
Bruno de Oliveira Abinader <bruno.d@partner.samsung.com>
|
||||
Bryan Dunsmore <dunsmoreb@gmail.com>
|
||||
Byron Williams <byron@112percent.com>
|
||||
@ -172,6 +181,7 @@ Ches Martin <ches@whiskeyandgrits.net>
|
||||
chitra
|
||||
Chloe <5paceToast@users.noreply.github.com>
|
||||
Chris Double <chris.double@double.co.nz>
|
||||
Chris Hellmuth <chellmuth@gmail.com>
|
||||
Chris Morgan <me@chrismorgan.info>
|
||||
Chris Nixon <chris.nixon@sigma.me.uk>
|
||||
Chris Peterson <cpeterson@mozilla.com>
|
||||
@ -179,14 +189,17 @@ Chris Pressey <cpressey@gmail.com>
|
||||
Chris Sainty <csainty@hotmail.com>
|
||||
Chris Shea <cmshea@gmail.com>
|
||||
Chris Thorn <chris@thorn.co>
|
||||
Christian Stadelmann <dev@genodeftest.de>
|
||||
Christoph Burgdorf <christoph.burgdorf@bvsn.org>
|
||||
Christopher Bergqvist <spambox0@digitalpoetry.se>
|
||||
Christopher Chambers <chris.chambers@peanutcode.com>
|
||||
Christopher Kendell <ckendell@outlook.com>
|
||||
Chris Wong <lambda.fairy@gmail.com>
|
||||
chromatic <chromatic@wgz.org>
|
||||
Chuck Bassett <iamchuckb@gmail.com>
|
||||
Chuck Ries <chuck.ries@gmail.com>
|
||||
Clark Gaebel <cg.wowus.cg@gmail.com>
|
||||
clatour <chandler.latour@gmail.com>
|
||||
Clifford Caoile <piyo@users.sf.net>
|
||||
Clinton Ryan <clint.ryan3@gmail.com>
|
||||
Cody P Schafer <dev@codyps.com>
|
||||
@ -201,10 +214,12 @@ Conrad Kleinespel <conradk@conradk.com>
|
||||
Corey Farwell <coreyf+rust@rwell.org>
|
||||
Corey Ford <corey@coreyford.name>
|
||||
Corey Richardson <corey@octayn.net>
|
||||
Cornel Punga <cornel.punga@gmail.com>
|
||||
crhino <piraino.chris@gmail.com>
|
||||
Cristian Kubis <cristian.kubis@tsunix.de>
|
||||
Cristi Burcă <scribu@gmail.com>
|
||||
critiqjo <john.ch.fr@gmail.com>
|
||||
Cruz Julian Bishop <cruzjbishop@gmail.com>
|
||||
Damian Gryski <damian@gryski.com>
|
||||
Damien Grassart <damien@grassart.com>
|
||||
Damien Radtke <dradtke@channeliq.com>
|
||||
@ -240,6 +255,7 @@ Darrell Hamilton <darrell.noice@gmail.com>
|
||||
Dave Herman <dherman@mozilla.com>
|
||||
Dave Hodder <dmh@dmh.org.uk>
|
||||
Dave Huseby <dhuseby@mozilla.com>
|
||||
David Campbell <dcampbell24@gmail.com>
|
||||
David Creswick <dcrewi@gyrae.net>
|
||||
David Forsythe <dforsythe@gmail.com>
|
||||
David Halperin <halperin.dr@gmail.com>
|
||||
@ -251,7 +267,9 @@ David Rajchenbach-Teller <dteller@mozilla.com>
|
||||
David Reid <dreid@dreid.org>
|
||||
David Renshaw <dwrenshaw@gmail.com>
|
||||
David Ross <daboross@daboross.net>
|
||||
David Stygstra <david.stygstra@gmail.com>
|
||||
David Vazgenovich Shakaryan <dvshakaryan@gmail.com>
|
||||
David Voit <david.voit@gmail.com>
|
||||
Davis Silverman <sinistersnare@gmail.com>
|
||||
defuz <defuz.net@gmail.com>
|
||||
Denis Defreyne <denis.defreyne@stoneship.org>
|
||||
@ -271,6 +289,7 @@ Dirk Leifeld <leifeld@posteo.de>
|
||||
Div Shekhar <div@pagerduty.com>
|
||||
diwic <diwic@users.noreply.github.com>
|
||||
DJUrsus <colinvh@divitu.com>
|
||||
dmgawel <dgkonik@gmail.com>
|
||||
Dmitry Ermolov <epdmitry@yandex.ru>
|
||||
Dmitry Promsky <dmitry@willworkforcookies.com>
|
||||
Dmitry Vasiliev <dima@hlabs.org>
|
||||
@ -290,6 +309,7 @@ Dylan Braithwaite <dylanbraithwaite1@gmail.com>
|
||||
Dylan Ede <dylanede@googlemail.com>
|
||||
Dzmitry Malyshau <kvarkus@gmail.com>
|
||||
Earl St Sauver <estsauver@gmail.com>
|
||||
econoplas <econoplas@gmail.com>
|
||||
Eduard Bopp <eduard.bopp@aepsil0n.de>
|
||||
Eduard Burtescu <edy.burt@gmail.com>
|
||||
Eduardo Bautista <me@eduardobautista.com>
|
||||
@ -297,6 +317,7 @@ Edward Wang <edward.yu.wang@gmail.com>
|
||||
Edward Z. Yang <ezyang@cs.stanford.edu>
|
||||
Ehsanul Hoque <ehsanul@ehsanul.com>
|
||||
Elantsev Serj <elantsev@yandex-team.ru>
|
||||
Eli Friedman <eli.friedman@gmail.com>
|
||||
eliovir <eliovir@gmail.com>
|
||||
Elliott Slaughter <elliottslaughter@gmail.com>
|
||||
Elly Fong-Jones <elly@leptoquark.net>
|
||||
@ -304,6 +325,8 @@ elszben <notgonna@tellyou>
|
||||
emanueLczirai <emanueLczirai@cryptoLab.net>
|
||||
Emanuel Rylke <ema-fox@web.de>
|
||||
Emeliov Dmitrii <demelev1990@gmail.com>
|
||||
Emilio Cobos Álvarez <ecoal95@gmail.com>
|
||||
Emily Dunham <edunham@mozilla.com>
|
||||
Eric Allen <ericpallen@gmail.com>
|
||||
Eric Biggers <ebiggers3@gmail.com>
|
||||
Eric Holk <eric.holk@gmail.com>
|
||||
@ -314,7 +337,9 @@ Erick Tryzelaar <erick.tryzelaar@gmail.com>
|
||||
Eric Martin <e.a.martin1337@gmail.com>
|
||||
Eric Platon <eric.platon@waku-waku.ne.jp>
|
||||
Eric Reed <ecreed@cs.washington.edu>
|
||||
Eric Ye <me@ericye16.com>
|
||||
Erik Lyon <elyon001@local.fake>
|
||||
Erik Michaels-Ober <sferik@gmail.com>
|
||||
Erik Price <erik.price16@gmail.com>
|
||||
Erik Rose <erik@mozilla.com>
|
||||
Erwan <erwan.ricq@gmail.com>
|
||||
@ -344,10 +369,12 @@ Florian Wilkens <mrfloya_github@outlook.com>
|
||||
Florian Zeitz <florob@babelmonkeys.de>
|
||||
fort <e@mail.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
frankamp <frankamp@gmail.com>
|
||||
Franklin Chen <franklinchen@franklinchen.com>
|
||||
Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
|
||||
free-Runner <aali07@students.poly.edu>
|
||||
FuGangqiang <fu_gangqiang@163.com>
|
||||
funkill <funkill2@gmail.com>
|
||||
g3xzh <g3xzh@yahoo.com>
|
||||
Gábor Horváth <xazax.hun@gmail.com>
|
||||
Gábor Lehel <glaebhoerl@gmail.com>
|
||||
@ -381,6 +408,7 @@ Greg Chapple <gregchapple1@gmail.com>
|
||||
Grigoriy <ohaistarlight@gmail.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com>
|
||||
Guillaume Pinot <texitoi@texitoi.eu>
|
||||
Gulshan Singh <gsingh2011@gmail.com>
|
||||
Gyorgy Andrasek <jurily@gmail.com>
|
||||
Haitao Li <lihaitao@gmail.com>
|
||||
Hajime Morrita <omo@dodgson.org>
|
||||
@ -419,6 +447,7 @@ Ivano Coppola <rgbfirefox@gmail.com>
|
||||
Ivan Petkov <ivanppetkov@gmail.com>
|
||||
Ivan Radanov Ivanov <ivanradanov@yahoo.co.uk>
|
||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Iven Hsu <ivenvd@gmail.com>
|
||||
Jack Heizer <jack.heizer@gmail.com>
|
||||
Jack Moffitt <jack@metajack.im>
|
||||
Jacob Edelman <edelman.jd@gmail.com>
|
||||
@ -428,6 +457,7 @@ Jacob Parker <j3parker@csclub.uwaterloo.ca>
|
||||
Jaemin Moon <jaemin.moon@samsung.com>
|
||||
Jag Talon <talon.jag@gmail.com>
|
||||
Jake Goulding <jake.goulding@gmail.com>
|
||||
Jake Hickey <empty@cqdr.es>
|
||||
Jake Kaufman <theevocater@gmail.com>
|
||||
Jake Kerr <kodafox@gmail.com>
|
||||
Jake Scott <jake.net@gmail.com>
|
||||
@ -439,7 +469,7 @@ James Hurst <jamesrhurst@users.noreply.github.com>
|
||||
James Lal <james@lightsofapollo.com>
|
||||
James Laverack <james@jameslaverack.com>
|
||||
jamesluke <jamesluke@users.noreply.github.com>
|
||||
James Miller <james@aatch.net>
|
||||
James Miller <bladeon@gmail.com>
|
||||
James Perry <james.austin.perry@gmail.com>
|
||||
James Rowe <jroweboy@gmail.com>
|
||||
James Sanders <sanderjd@gmail.com>
|
||||
@ -479,11 +509,13 @@ Jelte Fennema <github-tech@jeltef.nl>
|
||||
Jens Nockert <jens@nockert.se>
|
||||
Jeong YunWon <jeong@youknowone.org>
|
||||
Jeremy Letang <letang.jeremy@gmail.com>
|
||||
Jeremy Schlatter <jeremy.schlatter@gmail.com>
|
||||
Jesse Jones <jesse9jones@gmail.com>
|
||||
Jesse Luehrs <doy@tozt.net>
|
||||
Jesse Ray <jesse@localhost.localdomain>
|
||||
Jesse Ruderman <jruderman@gmail.com>
|
||||
Jessy Diamond Exum <jessy.diamondman@gmail.com>
|
||||
Jexell <Jexell@users.noreply.github.com>
|
||||
Jihyeok Seo <me@limeburst.net>
|
||||
Jihyun Yu <j.yu@navercorp.com>
|
||||
Jim Apple <jbapple+rust@google.com>
|
||||
@ -504,6 +536,7 @@ Johannes Löthberg <johannes@kyriasis.com>
|
||||
Johannes Muenzel <jmuenzel@gmail.com>
|
||||
Johannes Oertel <johannes.oertel@uni-due.de>
|
||||
Johann Hofmann <git@johann-hofmann.com>
|
||||
Johann Tuffe <tafia973@gmail.com>
|
||||
John Albietz <inthecloud247@gmail.com>
|
||||
John Barker <jebarker@gmail.com>
|
||||
John Clements <clements@racket-lang.org>
|
||||
@ -519,6 +552,7 @@ John Simon <john@johnsoft.com>
|
||||
John Talling <inrustwetrust@users.noreply.github.com>
|
||||
John Van Enk <vanenkj@gmail.com>
|
||||
John Zhang <john@zhang.io>
|
||||
joliv <joliv@users.noreply.github.com>
|
||||
Jonas Hietala <tradet.h@gmail.com>
|
||||
Jonathan Bailey <jbailey@mozilla.com>
|
||||
Jonathan Boyett <jonathan@failingservers.com>
|
||||
@ -545,6 +579,7 @@ Josh Matthews <josh@joshmatthews.net>
|
||||
Josh Stone <cuviper@gmail.com>
|
||||
Josh Triplett <josh@joshtriplett.org>
|
||||
Joshua Clark <joshua.clark@txstate.edu>
|
||||
Joshua Landau <joshua@landau.ws>
|
||||
Joshua Wise <joshua@joshuawise.com>
|
||||
Joshua Yanovski <pythonesque@gmail.com>
|
||||
JP-Ellis <coujellis@gmail.com>
|
||||
@ -586,6 +621,7 @@ KokaKiwi <kokakiwi+rust@kokakiwi.net>
|
||||
korenchkin <korenchkin2@gmail.com>
|
||||
Kostas Karachalios <vrinek@me.com>
|
||||
Krzysztof Drewniak <krzysdrewniak@gmail.com>
|
||||
Kubilay Kocak <koobs@users.noreply.github.com>
|
||||
kulakowski <george.kulakowski@gmail.com>
|
||||
kwantam <kwantam@gmail.com>
|
||||
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
|
||||
@ -601,6 +637,7 @@ Lee Jeffery <leejeffery@gmail.com>
|
||||
Lee Wondong <wdlee91@gmail.com>
|
||||
LemmingAvalanche <haugsbakk@yahoo.no>
|
||||
Lennart Kudling <github@kudling.de>
|
||||
Leo Correa <lcorr005@gmail.com>
|
||||
Leonids Maslovs <leonids.maslovs@galeoconsulting.com>
|
||||
Leo Testard <leo.testard@gmail.com>
|
||||
leunggamciu <gamciuleung@gmail.com>
|
||||
@ -610,6 +647,7 @@ Lindsey Kuper <lindsey@composition.al>
|
||||
Lionel Flandrin <lionel.flandrin@parrot.com>
|
||||
Logan Chien <tzuhsiang.chien@gmail.com>
|
||||
Loïc Damien <loic.damien@dzamlo.ch>
|
||||
Lorenz <lorenzb@student.ethz.ch>
|
||||
lpy <pylaurent1314@gmail.com>
|
||||
Luca Bruno <lucab@debian.org>
|
||||
lucy <ne.tetewi@gmail.com>
|
||||
@ -629,16 +667,21 @@ maikklein <maikklein@googlemail.com>
|
||||
Makoto Nakashima <makoto.nksm+github@gmail.com>
|
||||
Manish Goregaokar <manishsmail@gmail.com>
|
||||
Manuel Hoffmann <manuel@polythematik.de>
|
||||
marcell <marcell.pardavi@gmail.com>
|
||||
Marcel Müller <neikos@neikos.email>
|
||||
Marcel Rodrigues <marcelgmr@gmail.com>
|
||||
Marcus Klaas <mail@marcusklaas.nl>
|
||||
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
|
||||
Marijn Haverbeke <marijnh@gmail.com>
|
||||
Marin Atanasov Nikolov <dnaeon@gmail.com>
|
||||
Mário Feroldi <thelost-t@live.com>
|
||||
Mark Lacey <641@rudkx.com>
|
||||
Mark Mossberg <mark.mossberg@gmail.com>
|
||||
Mark Rowe <mrowe@bdash.net.nz>
|
||||
Mark Sinclair <mark.edward.x@gmail.com>
|
||||
Markus Siemens <siemens1993@gmail.com>
|
||||
Markus Unterwaditzer <markus@unterwaditzer.net>
|
||||
Markus Westerlind <marwes91@gmail.com>
|
||||
Mark Vian <mrv.caseus@gmail.com>
|
||||
Martin DeMello <martindemello@gmail.com>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
@ -648,6 +691,7 @@ Marvin Löbel <loebel.marvin@gmail.com>
|
||||
masklinn <github.com@masklinn.net>
|
||||
Matej Lach <matej.lach@gmail.com>
|
||||
Mateusz Czapliński <czapkofan@gmail.com>
|
||||
Mathieu David <mathieudavid@mathieudavid.org>
|
||||
Mathieu Poumeyrol <kali@zoy.org>
|
||||
Mathieu Rochette <mathieu@rochette.cc>
|
||||
Mathijs van de Nes <git@mathijs.vd-nes.nl>
|
||||
@ -655,6 +699,7 @@ Matt Brubeck <mbrubeck@limpet.net>
|
||||
Matt Carberry <carberry.matt@gmail.com>
|
||||
Matt Coffin <mcoffin13@gmail.com>
|
||||
Matt Cox <mattcoxpdx@gmail.com>
|
||||
Matthew Astley <mca@sanger.ac.uk>
|
||||
Matthew Auld <matthew.auld@intel.com>
|
||||
Matthew Iselin <matthew@theiselins.net>
|
||||
Matthew McPherrin <matthew@mcpherrin.ca>
|
||||
@ -670,6 +715,7 @@ Mátyás Mustoha <mmatyas@inf.u-szeged.hu>
|
||||
Maxime Quandalle <maxime@quandalle.com>
|
||||
Maximilian Haack <mxhaack@gmail.com>
|
||||
Maxim Kolganov <kolganov.mv@gmail.com>
|
||||
Max Jacobson <max@hardscrabble.net>
|
||||
Max Penet <max.penet@gmail.com>
|
||||
Maya Nitu <maya_nitu@yahoo.com>
|
||||
mchaput <matt@whoosh.ca>
|
||||
@ -685,7 +731,9 @@ Michael Darakananda <pongad@gmail.com>
|
||||
Michael Fairley <michaelfairley@gmail.com>
|
||||
Michael Gehring <mg@ebfe.org>
|
||||
Michael Kainer <kaini1123@gmail.com>
|
||||
Michael Layzell <michael@thelayzells.com>
|
||||
Michael Letterle <michael.letterle@gmail.com>
|
||||
Michael Macias <zaeleus@gmail.com>
|
||||
Michael Matuzak <mmatuzak@gmail.com>
|
||||
Michael Neumann <mneumann@ntecs.de>
|
||||
Michael Pankov <work@michaelpankov.com>
|
||||
@ -715,6 +763,7 @@ Mike Sampson <mike@sambodata.com>
|
||||
Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
|
||||
Mikko Perttunen <cyndis@kapsi.fi>
|
||||
mitchmindtree <mitchell.nordine@gmail.com>
|
||||
Mohammed Attia <skeuomorf@gmail.com>
|
||||
moonglum <moonglum@moonbeamlabs.com>
|
||||
mrec <mike.capp@gmail.com>
|
||||
mr.Shu <mr@shu.io>
|
||||
@ -727,6 +776,7 @@ nathan dotz <nathan.dotz@gmail.com>
|
||||
Nathan Froyd <froydnj@gmail.com>
|
||||
Nathaniel Herman <nherman@post.harvard.edu>
|
||||
Nathaniel Theis <nttheis@gmail.com>
|
||||
Nathan Long <nathanmlong@gmail.com>
|
||||
Nathan Stoddard <nstodda@purdue.edu>
|
||||
Nathan Typanski <ntypanski@gmail.com>
|
||||
Nathan Wilson <wilnathan@gmail.com>
|
||||
@ -739,6 +789,7 @@ Nicholas Bishop <nicholasbishop@gmail.com>
|
||||
Nicholas Mazzuca <npmazzuca@gmail.com>
|
||||
Nick Cameron <ncameron@mozilla.com>
|
||||
Nick Desaulniers <ndesaulniers@mozilla.com>
|
||||
Nick Fitzgerald <fitzgen@gmail.com>
|
||||
Nick Hamann <nick@wabbo.org>
|
||||
Nick Howell <howellnick@gmail.com>
|
||||
Nick Platt <platt.nicholas@gmail.com>
|
||||
@ -750,6 +801,7 @@ Nif Ward <nif.ward@gmail.com>
|
||||
Nikita Pekin <contact@nikitapek.in>
|
||||
Niklas Koep <niklas.koep@gmail.com>
|
||||
Niko Matsakis <niko@alum.mit.edu>
|
||||
Nils Liberg <nils@nilsliberg.se>
|
||||
Nils Winter <nils.winter@gmail.com>
|
||||
noam <noam@clusterfoo.com>
|
||||
Noam Yorav-Raphael <noamraph@gmail.com>
|
||||
@ -760,10 +812,13 @@ nsf <no.smile.face@gmail.com>
|
||||
nwin <nwin@users.noreply.github.com>
|
||||
Oak <White-Oak@users.noreply.github.com>
|
||||
OGINO Masanori <masanori.ogino@gmail.com>
|
||||
OlegTsyba <idethrone1@gmail.com>
|
||||
Oliver Schneider <git1984941651981@oli-obk.de>
|
||||
Oliver Schneider <github6541940@oli-obk.de>
|
||||
Olivier Saut <osaut@airpost.net>
|
||||
olivren <o.renaud@gmx.fr>
|
||||
Olle Jonsson <olle.jonsson@gmail.com>
|
||||
olombard <lombard-olivier@bbox.fr>
|
||||
Or Brostovski <tohava@gmail.com>
|
||||
Oren Hazi <oren.hazi@gmail.com>
|
||||
Or Neeman <oneeman@gmail.com>
|
||||
@ -776,6 +831,7 @@ P1start <rewi-github@whanau.org>
|
||||
Pablo Brasero <pablo@pablobm.com>
|
||||
Palmer Cox <p@lmercox.com>
|
||||
Paolo Falabella <paolo.falabella@gmail.com>
|
||||
Parker Moore <parkrmoore@gmail.com>
|
||||
Pascal Hertleif <killercup@gmail.com>
|
||||
Patrick Reisert <kpreisert@gmail.com>
|
||||
Patrick Walton <pcwalton@mimiga.net>
|
||||
@ -787,6 +843,7 @@ Paul Collier <paul@paulcollier.ca>
|
||||
Paul Collins <paul@ondioline.org>
|
||||
Paul Crowley <paulcrowley@google.com>
|
||||
Paul Faria <paul_faria@ultimatesoftware.com>
|
||||
Paul Oliver <puzza007@gmail.com>
|
||||
Paul Osborne <osbpau@gmail.com>
|
||||
Paul Quint <DrKwint@gmail.com>
|
||||
Paul Stansifer <paul.stansifer@gmail.com>
|
||||
@ -795,9 +852,10 @@ Pavel Panchekha <me@pavpanchekha.com>
|
||||
Pawel Olzacki <p.olzacki2@samsung.com>
|
||||
Pedro Larroy <pedro.larroy@here.com>
|
||||
Peer Aramillo Irizar <peer.aramillo.irizar@gmail.com>
|
||||
peferron <pe.ferron@gmail.com>
|
||||
Pete Hunt <petehunt@users.noreply.github.com>
|
||||
Peter Atashian <retep998@gmail.com>
|
||||
Peter Elmers <peter.elmers@rice.edu>
|
||||
Peter Elmers <peter.elmers@yahoo.com>
|
||||
Peter Hull <peterhull90@gmail.com>
|
||||
Peter Marheine <peter@taricorp.net>
|
||||
Peter Minten <peter@pminten.nl>
|
||||
@ -839,6 +897,8 @@ Ray Clanan <rclanan@utopianconcept.com>
|
||||
ray glover <ray@rayglover.net>
|
||||
reedlepee <reedlepee123@gmail.com>
|
||||
Reilly Watson <reillywatson@gmail.com>
|
||||
Rein Henrichs <reinh@reinh.com>
|
||||
Rémi Audebert <halfr@lse.epita.fr>
|
||||
Remi Rampin <remirampin@gmail.com>
|
||||
Renato Alves <alves.rjc@gmail.com>
|
||||
Renato Riccieri Santos Zannon <renato@rrsz.com.br>
|
||||
@ -876,15 +936,18 @@ Roy Frostig <rfrostig@mozilla.com>
|
||||
Rüdiger Sonderfeld <ruediger@c-plusplus.de>
|
||||
rundrop1 <rundrop1@zoho.com>
|
||||
Russell Johnston <rpjohnst@gmail.com>
|
||||
Russell McClellan <russell.mcclellan@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>
|
||||
らいどっと <ryogo.yoshimura@gmail.com>
|
||||
Sae-bom Kim <sae-bom.kim@samsung.com>
|
||||
Salem Talha <salem.a.talha@gmail.com>
|
||||
saml <saml@users.noreply.github.com>
|
||||
Samuel Chase <samebchase@gmail.com>
|
||||
Samuel Neves <sneves@dei.uc.pt>
|
||||
Sander Mathijs van Veen <smvv@kompiler.org>
|
||||
@ -895,7 +958,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>
|
||||
Scott Olson <scott@solson.me>
|
||||
Sean Bowe <ewillbefull@gmail.com>
|
||||
Sean Chalmers <sclhiannan@gmail.com>
|
||||
Sean Collins <sean@cllns.com>
|
||||
@ -932,6 +995,7 @@ Simon Kern <simon.kern@rwth-aachen.de>
|
||||
Simon Persson <simon@flaskpost.org>
|
||||
Simon Sapin <simon@exyr.org>
|
||||
Simon Wollwage <mail.wollwage@gmail.com>
|
||||
simplex <theemptystring@gmail.com>
|
||||
Sindre Johansen <sindre@sindrejohansen.no>
|
||||
sinkuu <sinkuupump@gmail.com>
|
||||
Skyler <skyler.lipthay@gmail.com>
|
||||
@ -945,6 +1009,7 @@ Stefan Bucur <stefan.bucur@epfl.ch>
|
||||
Stefan Plantikow <stefan.plantikow@googlemail.com>
|
||||
Stepan Koltsov <stepan.koltsov@gmail.com>
|
||||
Sterling Greene <sterling.greene@gmail.com>
|
||||
Steve Gury <steve.gury@gmail.com>
|
||||
Steve Klabnik <steve@steveklabnik.com>
|
||||
Steven Allen <steven@stebalien.com>
|
||||
Steven Crockett <crockett.j.steven@gmail.com>
|
||||
@ -952,9 +1017,11 @@ Steven De Coeyer <steven@banteng.be>
|
||||
Steven Fackler <sfackler@gmail.com>
|
||||
Steven Sheldon <steven@sasheldon.com>
|
||||
Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca>
|
||||
Steven Walter <stevenrwalter@gmail.com>
|
||||
Strahinja Val Markovic <val@markovic.io>
|
||||
Stuart Pernsteiner <stuart@pernsteiner.org>
|
||||
Subhash Bhushan <subhash.bhushan@kaybus.com>
|
||||
sumito3478 <sumito3478@gmail.com>
|
||||
Swaroop C H <swaroop@swaroopch.com>
|
||||
Sylvestre Ledru <sylvestre@debian.org>
|
||||
Tamir Duberstein <tamird@gmail.com>
|
||||
@ -975,6 +1042,7 @@ Thomas Backman <serenity@exscape.org>
|
||||
Thomas Bracht Laumann Jespersen <laumann.thomas@gmail.com>
|
||||
Thomas Daede <daede003@umn.edu>
|
||||
Thomas Jespersen <laumann.thomas@gmail.com>
|
||||
Thomas Karpiniec <tk@1.21jiggawatts.net>
|
||||
Tiago Nobrega <tigarmo@gmail.com>
|
||||
Tibor Benke <ihrwein@gmail.com>
|
||||
Till Hoeppner <till@hoeppner.ws>
|
||||
@ -986,6 +1054,7 @@ Tim Kuehn <tkuehn@cmu.edu>
|
||||
Timon Rapp <timon@zaeda.net>
|
||||
Timothée Ravier <tim@siosm.fr>
|
||||
Tim Parenti <timparenti@gmail.com>
|
||||
Tim Ringenbach <tim.ringenbach@gmail.com>
|
||||
Tim Taubert <tim@timtaubert.de>
|
||||
tinaun <tinagma@gmail.com>
|
||||
Tincan <tincann@users.noreply.github.com>
|
||||
@ -1046,11 +1115,15 @@ Volker Mische <volker.mische@gmail.com>
|
||||
Wade Mealing <wmealing@gmail.com>
|
||||
Wangshan Lu <wisagan@gmail.com>
|
||||
WebeWizard <webewizard@gmail.com>
|
||||
webmobster <webmobster@users.noreply.github.com>
|
||||
Wei-Ming Yang <rick68@users.noreply.github.com>
|
||||
Wendell Smith <wendell.smith@yale.edu>
|
||||
Wesley Wiser <wwiser@gmail.com>
|
||||
whataloadofwhat <unusualmoniker@gmail.com>
|
||||
wickerwaka <martin.donlon@gmail.com>
|
||||
Wilfred Hughes <me@wilfred.me.uk>
|
||||
Will Andrews <will@firepipe.net>
|
||||
Will Engler <engler.will@gmail.com>
|
||||
Will Hipschman <whipsch@gmail.com>
|
||||
William Ting <io@williamting.com>
|
||||
Willson Mock <willson.mock@gmail.com>
|
||||
@ -1058,12 +1131,15 @@ Will <will@glozer.net>
|
||||
Wojciech Ogrodowczyk <github@haikuco.de>
|
||||
wonyong kim <wonyong.kim@samsung.com>
|
||||
xales <xales@naveria.com>
|
||||
Xuefeng Wu <benewu@gmail.com>
|
||||
XuefengWu <benewu@gmail.com>
|
||||
Xuefeng Wu <xfwu@thoughtworks.com>
|
||||
Xue Fuqiao <xfq.free@gmail.com>
|
||||
Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
|
||||
YawarRaza7349 <YawarRaza7349@gmail.com>
|
||||
Yazhong Liu <yorkiefixer@gmail.com>
|
||||
Yehuda Katz <wycats@gmail.com>
|
||||
Yongqian Li <yongqli@kerrmetric.com>
|
||||
York Xiang <bombless@126.com>
|
||||
Young-il Choi <duddlf.choi@samsung.com>
|
||||
Youngmin Yoo <youngmin.yoo@samsung.com>
|
||||
@ -1071,6 +1147,7 @@ Youngsoo Son <ysson83@gmail.com>
|
||||
Young Wu <doomsplayer@gmail.com>
|
||||
Yuri Albuquerque <yuridenommus@gmail.com>
|
||||
Yuri Kunde Schlesner <yuriks@yuriks.net>
|
||||
Z1 <MazinZ1@users.noreply.github.com>
|
||||
Zach Kamsler <smoo.master@gmail.com>
|
||||
Zach Pomerantz <zmp@umich.edu>
|
||||
Zack Corr <zack@z0w0.me>
|
||||
|
@ -83,6 +83,21 @@ feature. We use the 'fork and pull' model described there.
|
||||
|
||||
Please make pull requests against the `master` branch.
|
||||
|
||||
Compiling all of `make check` can take a while. When testing your pull request,
|
||||
consider using one of the more specialized `make` targets to cut down on the
|
||||
amount of time you have to wait. You need to have built the compiler at least
|
||||
once before running these will work, but that’s only one full build rather than
|
||||
one each time.
|
||||
|
||||
$ make -j8 rustc-stage1 && make check-stage1
|
||||
|
||||
is one such example, which builds just `rustc`, and then runs the tests. If
|
||||
you’re adding something to the standard library, try
|
||||
|
||||
$ make -j8 check-stage1-std NO_REBUILD=1
|
||||
|
||||
This will not rebuild the compiler, but will run the tests.
|
||||
|
||||
All pull requests are reviewed by another person. We have a bot,
|
||||
@rust-highfive, that will automatically assign a random person to review your
|
||||
request.
|
||||
@ -108,14 +123,18 @@ will run all the tests on every platform we support. If it all works out,
|
||||
|
||||
[merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust
|
||||
|
||||
Speaking of tests, Rust has a comprehensive test suite. More information about
|
||||
it can be found
|
||||
[here](https://github.com/rust-lang/rust-wiki-backup/blob/master/Note-testsuite.md).
|
||||
|
||||
## Writing Documentation
|
||||
|
||||
Documentation improvements are very welcome. The source of `doc.rust-lang.org`
|
||||
is located in `src/doc` in the tree, and standard API documentation is generated
|
||||
from the source code itself.
|
||||
|
||||
Documentation pull requests function in the same as other pull requests, though
|
||||
you may see a slightly different form of `r+`:
|
||||
Documentation pull requests function in the same way as other pull requests,
|
||||
though you may see a slightly different form of `r+`:
|
||||
|
||||
@bors: r+ 38fe8d2 rollup
|
||||
|
||||
|
@ -62,6 +62,7 @@
|
||||
# * tidy-basic - show file / line stats
|
||||
# * tidy-errors - show the highest rustc error code
|
||||
# * tidy-features - show the status of language and lib features
|
||||
# * rustc-stage$(stage) - Only build up to a specific stage
|
||||
#
|
||||
# Then mix in some of these environment variables to harness the
|
||||
# ultimate power of The Rust Build System.
|
||||
@ -90,7 +91,7 @@
|
||||
#
|
||||
# # Rust recipes for build system success
|
||||
#
|
||||
# // Modifying libstd? Use this comment to run unit tests just on your change
|
||||
# // Modifying libstd? Use this command to run unit tests just on your change
|
||||
# make check-stage1-std NO_REBUILD=1 NO_BENCH=1
|
||||
#
|
||||
# // Added a run-pass test? Use this to test running your test
|
||||
|
@ -4,7 +4,7 @@ Rust is a fast systems programming language that guarantees
|
||||
memory safety and offers painless concurrency ([no data races]).
|
||||
It does not employ a garbage collector and has minimal runtime overhead.
|
||||
|
||||
This repo contains the code for `rustc`, the Rust compiler, as well
|
||||
This repo contains the code for the compiler (`rustc`), as well
|
||||
as standard libraries, tools and documentation for Rust.
|
||||
|
||||
[no data races]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html
|
||||
@ -73,7 +73,7 @@ Read ["Installing Rust"] from [The Book].
|
||||
```
|
||||
|
||||
3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed
|
||||
MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
|
||||
MSYS2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust.
|
||||
|
||||
4. Navigate to Rust's source code, configure and build it:
|
||||
|
||||
|
169
RELEASES.md
169
RELEASES.md
@ -1,3 +1,150 @@
|
||||
Version 1.2.0 (August 2015)
|
||||
===========================
|
||||
|
||||
* ~1200 changes, numerous bugfixes
|
||||
|
||||
Highlights
|
||||
----------
|
||||
|
||||
* [Dynamically-sized-type coercions][dst] allow smart pointer types
|
||||
like `Rc` to contain types without a fixed size, arrays and trait
|
||||
objects, finally enabling use of `Rc<[T]>` and completing the
|
||||
implementation of DST.
|
||||
* [Parallel codegen][parcodegen] is now working again, which can
|
||||
substantially speed up large builds in debug mode; It also gets
|
||||
another ~33% speedup when bootstrapping on a 4 core machine (using 8
|
||||
jobs). It's not enabled by default, but will be "in the near
|
||||
future". It can be activated with the `-C codegen-units=N` flag to
|
||||
`rustc`.
|
||||
|
||||
Breaking Changes
|
||||
----------------
|
||||
|
||||
* The [`to_uppercase`] and [`to_lowercase`] methods on `char` now do
|
||||
unicode case mapping, which is a previously-planned change in
|
||||
behavior and considered a bugfix.
|
||||
* [`mem::align_of`] now specifies [the *minimum alignment* for
|
||||
T][align], which is usually the alignment programs are interested
|
||||
in, and the same value reported by clang's
|
||||
`alignof`. [`mem::min_align_of`] is deprecated. This is not known to
|
||||
break real code.
|
||||
* [The `#[packed]` attribute is no longer silently accepted by the
|
||||
compiler][packed]. This attribute did nothing and code that
|
||||
mentioned it likely did not work as intended.
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
* Patterns with `ref mut` now correctly invoke [`DerefMut`] when
|
||||
matching against dereferencable values.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
* The [`Extend`] trait, which grows a collection from an iterator, is
|
||||
implemented over iterators of references, for `String`, `Vec`,
|
||||
`LinkedList`, `VecDeque`, `EnumSet`, `BinaryHeap`, `VecMap`,
|
||||
`BTreeSet` and `BTreeMap`. [RFC][extend-rfc].
|
||||
* The [`iter::once`] function returns an iterator that yields a single
|
||||
element.
|
||||
* The [`iter::empty`] function returns an iterator that yields no
|
||||
elements.
|
||||
* The [`matches`] and [`rmatches`] methods on `str` return iterators
|
||||
over substring matches.
|
||||
* [`Cell`] and [`RefCell`] both implement [`Eq`].
|
||||
* A number of methods for wrapping arithmetic are added to the
|
||||
integral types, [`wrapping_div`], [`wrapping_rem`],
|
||||
[`wrapping_neg`], [`wrapping_shl`], [`wrapping_shr`]. These are in
|
||||
addition to the existing [`wrapping_add`], [`wrapping_sub`], and
|
||||
[`wrapping_mul`] methods, and alternatives to the [`Wrapping`]
|
||||
type.. It is illegal for the default arithmetic operations in Rust
|
||||
to overflow; the desire to wrap must be explicit.
|
||||
* The `{:#?}` formatting specifier [displays the alternate,
|
||||
pretty-printed][debugfmt] form of the `Debug` formatter. This
|
||||
feature was actually introduced prior to 1.0 with little
|
||||
fanfare.
|
||||
* [`fmt::Formatter`] implements [`fmt::Write`], a `fmt`-specific trait
|
||||
for writing data to formatted strings, similar to [`io::Write`].
|
||||
* [`fmt::Formatter`] adds 'debug builder' methods, [`debug_struct`],
|
||||
[`debug_tuple`], [`debug_list`], [`debug_set`], [`debug_map`]. These
|
||||
are used by code generators to emit implementations of [`Debug`].
|
||||
* `str` has new [`to_uppercase`][strup] and [`to_lowercase`][strlow]
|
||||
methods that convert case, following Unicode case mapping.
|
||||
* It is now easier to handle to poisoned locks. The [`PoisonError`]
|
||||
type, returned by failing lock operations, exposes `into_inner`,
|
||||
`get_ref`, and `get_mut`, which all give access to the inner lock
|
||||
guard, and allow the poisoned lock to continue to operate. The
|
||||
`is_poisoned` method of [`RwLock`] and [`Mutex`] can poll for a
|
||||
poisoned lock without attempting to take the lock.
|
||||
* On Unix the [`FromRawFd`] trait is implemented for [`Stdio`], and
|
||||
[`AsRawFd`] for [`ChildStdin`], [`ChildStdout`], [`ChildStderr`].
|
||||
On Windows the `FromRawHandle` trait is implemented for `Stdio`,
|
||||
and `AsRawHandle` for `ChildStdin`, `ChildStdout`,
|
||||
`ChildStderr`.
|
||||
* [`io::ErrorKind`] has a new variant, `InvalidData`, which indicates
|
||||
malformed input.
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
* `rustc` employs smarter heuristics for guessing at [typos].
|
||||
* `rustc` emits more efficient code for [no-op conversions between
|
||||
unsafe pointers][nop].
|
||||
* Fat pointers are now [passed in pairs of immediate arguments][fat],
|
||||
resulting in faster compile times and smaller code.
|
||||
|
||||
[`Extend`]: http://doc.rust-lang.org/nightly/std/iter/trait.Extend.html
|
||||
[extend-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0839-embrace-extend-extinguish.md
|
||||
[`iter::once`]: http://doc.rust-lang.org/nightly/std/iter/fn.once.html
|
||||
[`iter::empty`]: http://doc.rust-lang.org/nightly/std/iter/fn.empty.html
|
||||
[`matches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.matches
|
||||
[`rmatches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatches
|
||||
[`Cell`]: http://doc.rust-lang.org/nightly/std/cell/struct.Cell.html
|
||||
[`RefCell`]: http://doc.rust-lang.org/nightly/std/cell/struct.RefCell.html
|
||||
[`wrapping_add`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_add
|
||||
[`wrapping_sub`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_sub
|
||||
[`wrapping_mul`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_mul
|
||||
[`wrapping_div`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_div
|
||||
[`wrapping_rem`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_rem
|
||||
[`wrapping_neg`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_neg
|
||||
[`wrapping_shl`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shl
|
||||
[`wrapping_shr`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shr
|
||||
[`Wrapping`]: http://doc.rust-lang.org/nightly/std/num/struct.Wrapping.html
|
||||
[`fmt::Formatter`]: http://doc.rust-lang.org/nightly/std/fmt/struct.Formatter.html
|
||||
[`fmt::Write`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Write.html
|
||||
[`io::Write`]: http://doc.rust-lang.org/nightly/std/io/trait.Write.html
|
||||
[`debug_struct`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_struct
|
||||
[`debug_tuple`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_tuple
|
||||
[`debug_list`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_list
|
||||
[`debug_set`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_set
|
||||
[`debug_map`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_map
|
||||
[`Debug`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
|
||||
[strup]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_uppercase
|
||||
[strlow]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase
|
||||
[`to_uppercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_uppercase
|
||||
[`to_lowercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_lowercase
|
||||
[`PoisonError`]: http://doc.rust-lang.org/nightly/std/sync/struct.PoisonError.html
|
||||
[`RwLock`]: http://doc.rust-lang.org/nightly/std/sync/struct.RwLock.html
|
||||
[`Mutex`]: http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html
|
||||
[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`Stdio`]: http://doc.rust-lang.org/nightly/std/process/struct.Stdio.html
|
||||
[`ChildStdin`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdin.html
|
||||
[`ChildStdout`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdout.html
|
||||
[`ChildStderr`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStderr.html
|
||||
[`io::ErrorKind`]: http://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html
|
||||
[debugfmt]: https://www.reddit.com/r/rust/comments/3ceaui/psa_produces_prettyprinted_debug_output/
|
||||
[`DerefMut`]: http://doc.rust-lang.org/nightly/std/ops/trait.DerefMut.html
|
||||
[`mem::align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.align_of.html
|
||||
[align]: https://github.com/rust-lang/rust/pull/25646
|
||||
[`mem::min_align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.min_align_of.html
|
||||
[typos]: https://github.com/rust-lang/rust/pull/26087
|
||||
[nop]: https://github.com/rust-lang/rust/pull/26336
|
||||
[fat]: https://github.com/rust-lang/rust/pull/26411
|
||||
[dst]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
[parcodegen]: https://github.com/rust-lang/rust/pull/26018
|
||||
[packed]: https://github.com/rust-lang/rust/pull/25541
|
||||
|
||||
Version 1.1.0 (June 2015)
|
||||
=========================
|
||||
|
||||
@ -6,17 +153,16 @@ Version 1.1.0 (June 2015)
|
||||
Highlights
|
||||
----------
|
||||
|
||||
* The [`std::fs` module has been expanded][fs-expand] to expand the set of
|
||||
* The [`std::fs` module has been expanded][fs] to expand the set of
|
||||
functionality exposed:
|
||||
* `DirEntry` now supports optimizations like `file_type` and `metadata` which
|
||||
don't incur a syscall on some platforms.
|
||||
* A `symlink_metadata` function has been added.
|
||||
* The `fs::Metadata` structure now lowers to its OS counterpart, providing
|
||||
access to all underlying information.
|
||||
* The compiler contains extended explanations of many errors. When it
|
||||
emits such an error it also suggests using the `--explain` flag to
|
||||
read the extended explanations, which are also [cataloged on the web
|
||||
site][err].
|
||||
* The compiler now contains extended explanations of many errors. When an error
|
||||
with an explanation occurs the compiler suggests using the `--explain` flag
|
||||
to read the explanation. Error explanations are also [available online][err-index].
|
||||
* Thanks to multiple [improvements][sk] to [type checking][pre], as
|
||||
well as other work, the time to bootstrap the compiler decreased by
|
||||
32%.
|
||||
@ -24,11 +170,11 @@ Highlights
|
||||
Libraries
|
||||
---------
|
||||
|
||||
* The `str::split_whitespace` method splits a string on unicode
|
||||
* The [`str::split_whitespace`] method splits a string on unicode
|
||||
whitespace boundaries.
|
||||
* On both Windows and Unix, new extension traits provide conversion of
|
||||
I/O types to and from the underlying system handles. On Unix, these
|
||||
traits are [`FrowRawFd`] and [`AsRawFd`], on Windows `FromRawHandle`
|
||||
traits are [`FromRawFd`] and [`AsRawFd`], on Windows `FromRawHandle`
|
||||
and `AsRawHandle`. These are implemented for `File`, `TcpStream`,
|
||||
`TcpListener`, and `UpdSocket`. Further implementations for
|
||||
`std::process` will be stabilized later.
|
||||
@ -80,15 +226,14 @@ Misc
|
||||
* [The `drop_with_repr_extern` lint warns about mixing `repr(C)`
|
||||
with `Drop`][drop].
|
||||
|
||||
[`split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
|
||||
[`Iterator::cloned`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cloned
|
||||
[`str::split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
|
||||
[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`std::os::unix::symlink`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html
|
||||
[`IntoIterator`]: http://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html
|
||||
[`From`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html
|
||||
[rf]: https://github.com/rust-lang/rust/pull/24491
|
||||
[err]: http://doc.rust-lang.org/error-index.html
|
||||
[err-index]: http://doc.rust-lang.org/error-index.html
|
||||
[sk]: https://github.com/rust-lang/rust/pull/24615
|
||||
[pre]: https://github.com/rust-lang/rust/pull/25323
|
||||
[file]: https://github.com/rust-lang/rust/pull/24598
|
||||
@ -251,7 +396,6 @@ Misc
|
||||
[sw]: https://github.com/rust-lang/rfcs/blob/master/text/1054-str-words.md
|
||||
[th]: https://github.com/rust-lang/rfcs/blob/master/text/0909-move-thread-local-to-std-thread.md
|
||||
[send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md
|
||||
[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html
|
||||
[moar-ufcs]: https://github.com/rust-lang/rust/pull/22172
|
||||
[prim-inherent]: https://github.com/rust-lang/rust/pull/23104
|
||||
[overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
|
||||
@ -261,12 +405,10 @@ Misc
|
||||
[string-pattern]: https://github.com/rust-lang/rust/pull/22466
|
||||
[oibit-final]: https://github.com/rust-lang/rust/pull/21689
|
||||
[reflect]: https://github.com/rust-lang/rust/pull/23712
|
||||
[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md
|
||||
[conversion]: https://github.com/rust-lang/rfcs/pull/529
|
||||
[num-traits]: https://github.com/rust-lang/rust/pull/23549
|
||||
[index-value]: https://github.com/rust-lang/rust/pull/23601
|
||||
[dropck]: https://github.com/rust-lang/rfcs/pull/769
|
||||
[fundamental]: https://github.com/rust-lang/rfcs/pull/1023
|
||||
[ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee
|
||||
[fn-inherit]: https://github.com/rust-lang/rust/pull/23282
|
||||
[fn-blanket]: https://github.com/rust-lang/rust/pull/23895
|
||||
@ -369,7 +511,6 @@ Version 1.0.0-alpha.2 (February 2015)
|
||||
[osstr]: https://github.com/rust-lang/rust/pull/21488
|
||||
[osstr-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md
|
||||
[Self]: https://github.com/rust-lang/rust/pull/22158
|
||||
[ufcs]: https://github.com/rust-lang/rust/pull/21077
|
||||
[ufcs-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md
|
||||
[un]: https://github.com/rust-lang/rust/pull/22256
|
||||
|
||||
|
234
configure
vendored
234
configure
vendored
@ -283,7 +283,7 @@ opt_core() {
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ ! -z "$META" ]
|
||||
if [ -n "$META" ]
|
||||
then
|
||||
OP="$OP=<$META>"
|
||||
fi
|
||||
@ -317,12 +317,23 @@ envopt() {
|
||||
fi
|
||||
|
||||
# If script or environment provided a value, save it.
|
||||
if [ ! -z "$VV" ]
|
||||
if [ -n "$VV" ]
|
||||
then
|
||||
putvar $V
|
||||
fi
|
||||
}
|
||||
|
||||
enable_if_not_disabled() {
|
||||
local OP=$1
|
||||
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
|
||||
local ENAB_V="CFG_ENABLE_$UOP"
|
||||
local EXPLICITLY_DISABLED="CFG_DISABLE_${UOP}_PROVIDED"
|
||||
eval VV=\$$EXPLICITLY_DISABLED
|
||||
if [ -z "$VV" ]; then
|
||||
eval $ENAB_V=1
|
||||
fi
|
||||
}
|
||||
|
||||
to_llvm_triple() {
|
||||
case $1 in
|
||||
i686-w64-mingw32) echo i686-pc-windows-gnu ;;
|
||||
@ -405,6 +416,10 @@ case $CFG_OSTYPE in
|
||||
CFG_OSTYPE=unknown-openbsd
|
||||
;;
|
||||
|
||||
NetBSD)
|
||||
CFG_OSTYPE=unknown-netbsd
|
||||
;;
|
||||
|
||||
Darwin)
|
||||
CFG_OSTYPE=apple-darwin
|
||||
;;
|
||||
@ -667,10 +682,12 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then
|
||||
CFG_DISABLE_OPTIMIZE=1
|
||||
CFG_DISABLE_OPTIMIZE_CXX=1
|
||||
fi
|
||||
CFG_ENABLE_DEBUG_ASSERTIONS=1
|
||||
CFG_ENABLE_DEBUG_JEMALLOC=1
|
||||
CFG_ENABLE_DEBUGINFO=1
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
|
||||
# Set following variables to 1 unless setting already provided
|
||||
enable_if_not_disabled debug-assertions
|
||||
enable_if_not_disabled debug-jemalloc
|
||||
enable_if_not_disabled debuginfo
|
||||
enable_if_not_disabled llvm-assertions
|
||||
fi
|
||||
|
||||
# OK, now write the debugging options
|
||||
@ -750,7 +767,7 @@ 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" ]
|
||||
if [ -n "$CFG_ANTLR4" ]
|
||||
then
|
||||
probe CFG_JAVAC javac
|
||||
fi
|
||||
@ -769,14 +786,14 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_GDB" ]
|
||||
if [ -n "$CFG_GDB" ]
|
||||
then
|
||||
# Store GDB's version
|
||||
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
|
||||
putvar CFG_GDB_VERSION
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_LLDB" ]
|
||||
if [ -n "$CFG_LLDB" ]
|
||||
then
|
||||
# Store LLDB's version
|
||||
CFG_LLDB_VERSION=$($CFG_LLDB --version 2>/dev/null | head -1)
|
||||
@ -802,7 +819,7 @@ step_msg "looking for target specific programs"
|
||||
|
||||
probe CFG_ADB adb
|
||||
|
||||
if [ ! -z "$CFG_PANDOC" ]
|
||||
if [ -n "$CFG_PANDOC" ]
|
||||
then
|
||||
# Extract "MAJOR MINOR" from Pandoc's version number
|
||||
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' |
|
||||
@ -828,7 +845,7 @@ then
|
||||
BIN_SUF=.exe
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_ENABLE_LOCAL_RUST" ]
|
||||
if [ -n "$CFG_ENABLE_LOCAL_RUST" ]
|
||||
then
|
||||
system_rustc=$(which rustc)
|
||||
if [ -f ${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF} ]
|
||||
@ -899,20 +916,32 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
# If the clang isn't already enabled, check for GCC, and if it is missing, turn
|
||||
# on clang as a backup.
|
||||
if [ -z "$CFG_ENABLE_CLANG" ]
|
||||
then
|
||||
CFG_GCC_VERSION=$("$CFG_GCC" --version 2>&1)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
step_msg "GCC not installed, will try using Clang"
|
||||
CFG_ENABLE_CLANG=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Okay, at this point, we have made up our minds about whether we are
|
||||
# going to force CFG_ENABLE_CLANG or not; save the setting if so.
|
||||
if [ ! -z "$CFG_ENABLE_CLANG" ]
|
||||
if [ -n "$CFG_ENABLE_CLANG" ]
|
||||
then
|
||||
putvar CFG_ENABLE_CLANG
|
||||
fi
|
||||
|
||||
# Same with jemalloc. save the setting here.
|
||||
if [ ! -z "$CFG_DISABLE_JEMALLOC" ]
|
||||
if [ -n "$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" ]
|
||||
if [ -n "$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"
|
||||
|
||||
@ -941,7 +970,7 @@ fi
|
||||
# CFG_ENABLE_CLANG is set, that indicates that we are opting into
|
||||
# running such safeguards.
|
||||
|
||||
if [ ! -z "$CC" ]
|
||||
if [ -n "$CC" ]
|
||||
then
|
||||
msg "skipping compiler inference steps; using provided CC=$CC"
|
||||
CFG_CC="$CC"
|
||||
@ -954,7 +983,7 @@ then
|
||||
putvar CFG_USING_CLANG
|
||||
fi
|
||||
else
|
||||
if [ ! -z "$CFG_ENABLE_CLANG" ]
|
||||
if [ -n "$CFG_ENABLE_CLANG" ]
|
||||
then
|
||||
if [ -z "$CFG_CLANG" ]
|
||||
then
|
||||
@ -968,47 +997,59 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_ENABLE_CLANG" ]
|
||||
if [ -n "$CFG_ENABLE_CLANG" ]
|
||||
then
|
||||
case "$CC" in
|
||||
(''|*clang)
|
||||
CFG_CLANG_VERSION=$($CFG_CC \
|
||||
--version \
|
||||
| grep version \
|
||||
| sed 's/.*\(version .*\)/\1/; s/.*based on \(LLVM .*\))/\1/' \
|
||||
| cut -d ' ' -f 2)
|
||||
CFG_CLANG_REPORTED_VERSION=$($CFG_CC --version | grep version)
|
||||
|
||||
case $CFG_CLANG_VERSION in
|
||||
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7*)
|
||||
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
|
||||
if [ -z "$CC" ]
|
||||
then
|
||||
CFG_CC="clang"
|
||||
CFG_CXX="clang++"
|
||||
fi
|
||||
;;
|
||||
(*)
|
||||
err "bad CLANG version: $CFG_CLANG_VERSION, need >=3.0svn"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
(*)
|
||||
msg "skipping CFG_ENABLE_CLANG version check; provided CC=$CC"
|
||||
;;
|
||||
if [[ $CFG_CLANG_REPORTED_VERSION == *"(based on LLVM "* ]]
|
||||
then
|
||||
CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*(based on LLVM \(.*\))/\1/')
|
||||
elif [[ $CFG_CLANG_REPORTED_VERSION == "Apple LLVM"* ]]
|
||||
then
|
||||
CFG_OSX_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/')
|
||||
else
|
||||
CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/')
|
||||
fi
|
||||
|
||||
if [ -n "$CFG_OSX_CLANG_VERSION" ]
|
||||
then
|
||||
case $CFG_OSX_CLANG_VERSION in
|
||||
(7.0*)
|
||||
step_msg "found ok version of APPLE CLANG: $CFG_OSX_CLANG_VERSION"
|
||||
;;
|
||||
(*)
|
||||
err "bad APPLE CLANG version: $CFG_OSX_CLANG_VERSION, need >=7.0"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
case $CFG_CLANG_VERSION in
|
||||
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7*)
|
||||
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
|
||||
;;
|
||||
(*)
|
||||
err "bad CLANG version: $CFG_CLANG_VERSION, need >=3.0svn"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "$CC" ]
|
||||
then
|
||||
CFG_CC="clang"
|
||||
CFG_CXX="clang++"
|
||||
fi
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_ENABLE_CCACHE" ]
|
||||
if [ -n "$CFG_ENABLE_CCACHE" ]
|
||||
then
|
||||
if [ -z "$CC" ]
|
||||
if [ -z "$CFG_CCACHE" ]
|
||||
then
|
||||
if [ -z "$CFG_CCACHE" ]
|
||||
then
|
||||
err "ccache requested but not found"
|
||||
fi
|
||||
|
||||
CFG_CC="ccache $CFG_CC"
|
||||
err "ccache requested but not found"
|
||||
fi
|
||||
|
||||
CFG_CC="ccache $CFG_CC"
|
||||
fi
|
||||
|
||||
if [ -z "$CC" -a -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
|
||||
@ -1102,7 +1143,7 @@ do
|
||||
fi
|
||||
;;
|
||||
|
||||
x86_64-*-msvc)
|
||||
*-msvc)
|
||||
# Currently the build system is not configured to build jemalloc
|
||||
# with MSVC, so we omit this optional dependency.
|
||||
step_msg "targeting MSVC, disabling jemalloc"
|
||||
@ -1142,22 +1183,45 @@ do
|
||||
CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
|
||||
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
|
||||
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
|
||||
CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe"
|
||||
CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe"
|
||||
CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe"
|
||||
putvar CFG_MSVC_ROOT
|
||||
|
||||
case $i in
|
||||
x86_64-*)
|
||||
bits=x86_64
|
||||
msvc_part=amd64
|
||||
;;
|
||||
i686-*)
|
||||
bits=i386
|
||||
msvc_part=
|
||||
;;
|
||||
*)
|
||||
err "can only target x86 targets for MSVC"
|
||||
;;
|
||||
esac
|
||||
bindir="${CFG_MSVC_ROOT}/VC/bin"
|
||||
if [ -n "$msvc_part" ]; then
|
||||
bindir="$bindir/$msvc_part"
|
||||
fi
|
||||
eval CFG_MSVC_BINDIR_$bits="\"$bindir\""
|
||||
eval CFG_MSVC_CL_$bits="\"$bindir/cl.exe\""
|
||||
eval CFG_MSVC_LIB_$bits="\"$bindir/lib.exe\""
|
||||
eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\""
|
||||
|
||||
vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat"
|
||||
CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%")
|
||||
include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%")
|
||||
need_ok "failed to learn about MSVC's INCLUDE"
|
||||
CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%")
|
||||
lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%")
|
||||
need_ok "failed to learn about MSVC's LIB"
|
||||
|
||||
putvar CFG_MSVC_ROOT
|
||||
putvar CFG_MSVC_CL
|
||||
putvar CFG_MSVC_LIB
|
||||
putvar CFG_MSVC_LINK
|
||||
putvar CFG_MSVC_INCLUDE_PATH
|
||||
putvar CFG_MSVC_LIB_PATH
|
||||
eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\""
|
||||
eval CFG_MSVC_LIB_PATH_${bits}="\"$lib_path\""
|
||||
|
||||
putvar CFG_MSVC_BINDIR_${bits}
|
||||
putvar CFG_MSVC_CL_${bits}
|
||||
putvar CFG_MSVC_LIB_${bits}
|
||||
putvar CFG_MSVC_LINK_${bits}
|
||||
putvar CFG_MSVC_INCLUDE_PATH_${bits}
|
||||
putvar CFG_MSVC_LIB_PATH_${bits}
|
||||
;;
|
||||
|
||||
*)
|
||||
@ -1165,7 +1229,7 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -z "$CFG_PERF" ]
|
||||
if [ -n "$CFG_PERF" ]
|
||||
then
|
||||
HAVE_PERF_LOGFD=`$CFG_PERF stat --log-fd 2>&1 | grep 'unknown option'`
|
||||
if [ -z "$HAVE_PERF_LOGFD" ];
|
||||
@ -1275,11 +1339,11 @@ then
|
||||
"${CFG_GIT}" submodule init
|
||||
|
||||
# Disable submodules that we're not using
|
||||
if [ ! -z "${CFG_LLVM_ROOT}" ]; then
|
||||
if [ -n "${CFG_LLVM_ROOT}" ]; then
|
||||
msg "git: submodule deinit src/llvm"
|
||||
"${CFG_GIT}" submodule deinit src/llvm
|
||||
fi
|
||||
if [ ! -z "${CFG_JEMALLOC_ROOT}" ]; then
|
||||
if [ -n "${CFG_JEMALLOC_ROOT}" ]; then
|
||||
msg "git: submodule deinit src/jemalloc"
|
||||
"${CFG_GIT}" submodule deinit src/jemalloc
|
||||
fi
|
||||
@ -1326,7 +1390,7 @@ do
|
||||
if [ -z $CFG_LLVM_ROOT ]
|
||||
then
|
||||
LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
|
||||
if [ ! -z "$CFG_DISABLE_OPTIMIZE_LLVM" ]
|
||||
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
|
||||
then
|
||||
LLVM_DBG_OPTS="--enable-debug-symbols --disable-optimized"
|
||||
# Just use LLVM straight from its build directory to
|
||||
@ -1382,7 +1446,7 @@ do
|
||||
msg "configuring LLVM for $t with cmake"
|
||||
|
||||
CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF"
|
||||
if [ ! -z "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
|
||||
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"
|
||||
else
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release"
|
||||
@ -1396,8 +1460,19 @@ do
|
||||
|
||||
msg "configuring LLVM with:"
|
||||
msg "$CMAKE_ARGS"
|
||||
case "$t" in
|
||||
x86_64-*)
|
||||
generator="Visual Studio 12 2013 Win64"
|
||||
;;
|
||||
i686-*)
|
||||
generator="Visual Studio 12 2013"
|
||||
;;
|
||||
*)
|
||||
err "can only build LLVM for x86 platforms"
|
||||
;;
|
||||
esac
|
||||
(cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \
|
||||
-G "Visual Studio 12 2013 Win64" \
|
||||
-G "$generator" \
|
||||
$CMAKE_ARGS)
|
||||
need_ok "LLVM cmake configure failed"
|
||||
fi
|
||||
@ -1463,11 +1538,26 @@ do
|
||||
|
||||
(*)
|
||||
msg "inferring LLVM_CXX/CC from CXX/CC = $CXX/$CC"
|
||||
LLVM_CXX_32="$CXX"
|
||||
LLVM_CC_32="$CC"
|
||||
if [ -n "$CFG_ENABLE_CCACHE" ]
|
||||
then
|
||||
if [ -z "$CFG_CCACHE" ]
|
||||
then
|
||||
err "ccache requested but not found"
|
||||
fi
|
||||
|
||||
LLVM_CXX_32="ccache $CXX"
|
||||
LLVM_CC_32="ccache $CC"
|
||||
|
||||
LLVM_CXX_64="ccache $CXX"
|
||||
LLVM_CC_64="ccache $CC"
|
||||
else
|
||||
LLVM_CXX_32="$CXX"
|
||||
LLVM_CC_32="$CC"
|
||||
|
||||
LLVM_CXX_64="$CXX"
|
||||
LLVM_CC_64="$CC"
|
||||
fi
|
||||
|
||||
LLVM_CXX_64="$CXX"
|
||||
LLVM_CC_64="$CC"
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1582,20 +1672,20 @@ putvar CFG_MANDIR
|
||||
|
||||
# Avoid spurious warnings from clang by feeding it original source on
|
||||
# ccache-miss rather than preprocessed input.
|
||||
if [ ! -z "$CFG_ENABLE_CCACHE" ] && [ ! -z "$CFG_USING_CLANG" ]
|
||||
if [ -n "$CFG_ENABLE_CCACHE" ] && [ -n "$CFG_USING_CLANG" ]
|
||||
then
|
||||
CFG_CCACHE_CPP2=1
|
||||
putvar CFG_CCACHE_CPP2
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_ENABLE_CCACHE" ]
|
||||
if [ -n "$CFG_ENABLE_CCACHE" ]
|
||||
then
|
||||
CFG_CCACHE_BASEDIR=${CFG_SRC_DIR}
|
||||
putvar CFG_CCACHE_BASEDIR
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -z $BAD_PANDOC ]
|
||||
if [ -n $BAD_PANDOC ]
|
||||
then
|
||||
CFG_PANDOC=
|
||||
putvar CFG_PANDOC
|
||||
|
29
mk/cfg/i686-pc-windows-msvc.mk
Normal file
29
mk/cfg/i686-pc-windows-msvc.mk
Normal file
@ -0,0 +1,29 @@
|
||||
# i686-pc-windows-msvc configuration
|
||||
CC_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
|
||||
LINK_i686-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo
|
||||
CXX_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
|
||||
CPP_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
|
||||
AR_i686-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo
|
||||
CFG_LIB_NAME_i686-pc-windows-msvc=$(1).dll
|
||||
CFG_STATIC_LIB_NAME_i686-pc-windows-msvc=$(1).lib
|
||||
CFG_LIB_GLOB_i686-pc-windows-msvc=$(1)-*.{dll,lib}
|
||||
CFG_LIB_DSYM_GLOB_i686-pc-windows-msvc=$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_i686-pc-windows-msvc :=
|
||||
CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD
|
||||
CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD
|
||||
CFG_GCCISH_LINK_FLAGS_i686-pc-windows-msvc :=
|
||||
CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc :=
|
||||
CFG_LLC_FLAGS_i686-pc-windows-msvc :=
|
||||
CFG_INSTALL_NAME_i686-pc-windows-msvc =
|
||||
CFG_EXE_SUFFIX_i686-pc-windows-msvc := .exe
|
||||
CFG_WINDOWSY_i686-pc-windows-msvc := 1
|
||||
CFG_UNIXY_i686-pc-windows-msvc :=
|
||||
CFG_LDPATH_i686-pc-windows-msvc :=
|
||||
CFG_RUN_i686-pc-windows-msvc=$(2)
|
||||
CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2))
|
||||
CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32
|
||||
|
||||
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
|
||||
# bootstrapping from itself. This is relevant during stage0, and other parts of
|
||||
# the build system take this into account.
|
||||
BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu
|
22
mk/cfg/i686-unknown-freebsd.mk
Normal file
22
mk/cfg/i686-unknown-freebsd.mk
Normal file
@ -0,0 +1,22 @@
|
||||
# i686-unknown-freebsd configuration
|
||||
CC_i686-unknown-freebsd=$(CC)
|
||||
CXX_i686-unknown-freebsd=$(CXX)
|
||||
CPP_i686-unknown-freebsd=$(CPP)
|
||||
AR_i686-unknown-freebsd=$(AR)
|
||||
CFG_LIB_NAME_i686-unknown-freebsd=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_i686-unknown-freebsd=lib$(1).a
|
||||
CFG_LIB_GLOB_i686-unknown-freebsd=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_i686-unknown-freebsd=$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_i686-unknown-freebsd := -m32 -arch i386 -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -Wall -Werror -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-unknown-freebsd := -m32 -shared -fPIC -g -pthread -lrt
|
||||
CFG_GCCISH_DEF_FLAG_i686-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_i686-unknown-freebsd :=
|
||||
CFG_INSTALL_NAME_i686-unknown-freebsd =
|
||||
CFG_EXE_SUFFIX_i686-unknown-freebsd :=
|
||||
CFG_WINDOWSY_i686-unknown-freebsd :=
|
||||
CFG_UNIXY_i686-unknown-freebsd := 1
|
||||
CFG_LDPATH_i686-unknown-freebsd :=
|
||||
CFG_RUN_i686-unknown-freebsd=$(2)
|
||||
CFG_RUN_TARG_i686-unknown-freebsd=$(call CFG_RUN_i686-unknown-freebsd,,$(2))
|
||||
CFG_GNU_TRIPLE_i686-unknown-freebsd := i686-unknown-freebsd
|
@ -1,9 +1,9 @@
|
||||
# x86_64-pc-windows-msvc configuration
|
||||
CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
|
||||
LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo
|
||||
CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
|
||||
CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
|
||||
AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo
|
||||
CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
|
||||
LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK_x86_64)" -nologo
|
||||
CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
|
||||
CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
|
||||
AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB_x86_64)" -nologo
|
||||
CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll
|
||||
CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib
|
||||
CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib}
|
||||
@ -23,64 +23,6 @@ CFG_RUN_x86_64-pc-windows-msvc=$(2)
|
||||
CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2))
|
||||
CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32
|
||||
|
||||
# These two environment variables are scraped by the `./configure` script and
|
||||
# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
|
||||
# for `link.exe` to find standard libraries (the LIB variable).
|
||||
ifdef CFG_MSVC_INCLUDE_PATH
|
||||
export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
|
||||
endif
|
||||
ifdef CFG_MSVC_LIB_PATH
|
||||
export LIB := $(CFG_MSVC_LIB_PATH)
|
||||
endif
|
||||
|
||||
# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
|
||||
# but it's not the one that we want. As a result we make sure that our detected
|
||||
# `link.exe` shows up in PATH first.
|
||||
ifdef CFG_MSVC_LINK
|
||||
export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
|
||||
endif
|
||||
|
||||
# There are more comments about this available in the target specification for
|
||||
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
|
||||
# instead of `lib.exe` for assembling archives, so we need to inject this custom
|
||||
# dependency here.
|
||||
NATIVE_TOOL_DEPS_core_T_x86_64-pc-windows-msvc += llvm-ar.exe
|
||||
INSTALLED_BINS_x86_64-pc-windows-msvc += llvm-ar.exe
|
||||
|
||||
# When working with MSVC on windows, each DLL needs to explicitly declare its
|
||||
# interface to the outside world through some means. The options for doing so
|
||||
# include:
|
||||
#
|
||||
# 1. A custom attribute on each function itself
|
||||
# 2. A linker argument saying what to export
|
||||
# 3. A file which lists all symbols that need to be exported
|
||||
#
|
||||
# The Rust compiler takes care (1) for us for all Rust code by annotating all
|
||||
# public-facing functions with dllexport, but we have a few native dependencies
|
||||
# which need to cross the DLL boundary. The most important of these dependencies
|
||||
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
|
||||
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
|
||||
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
|
||||
#
|
||||
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
|
||||
# Windows for us, so we're forced to do it ourselves if we want it (which seems
|
||||
# like the path of least resistance right now). To do this we generate a `.DEF`
|
||||
# file [1] which we then custom-pass to the linker when building the rustc_llvm
|
||||
# crate. This DEF file list all symbols that are exported from
|
||||
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
|
||||
#
|
||||
# Fun times!
|
||||
#
|
||||
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
|
||||
RUSTFLAGS_rustc_llvm_T_x86_64-pc-windows-msvc += \
|
||||
-C link-args="-DEF:x86_64-pc-windows-msvc/rt/rustc_llvm.def"
|
||||
CUSTOM_DEPS_rustc_llvm_T_x86_64-pc-windows-msvc += \
|
||||
x86_64-pc-windows-msvc/rt/rustc_llvm.def
|
||||
|
||||
x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \
|
||||
$(S)src/librustc_llvm/lib.rs
|
||||
$(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA)
|
||||
|
||||
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
|
||||
# bootstrapping from itself. This is relevant during stage0, and other parts of
|
||||
# the build system take this into account.
|
||||
|
22
mk/cfg/x86_64-unknown-netbsd.mk
Normal file
22
mk/cfg/x86_64-unknown-netbsd.mk
Normal file
@ -0,0 +1,22 @@
|
||||
# x86_64-unknown-netbsd configuration
|
||||
CC_x86_64-unknown-netbsd=$(CC)
|
||||
CXX_x86_64-unknown-netbsd=$(CXX)
|
||||
CPP_x86_64-unknown-netbsd=$(CPP)
|
||||
AR_x86_64-unknown-netbsd=$(AR)
|
||||
CFG_LIB_NAME_x86_64-unknown-netbsd=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a
|
||||
CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_x86_64-unknown-netbsd :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-netbsd =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-netbsd :=
|
||||
CFG_WINDOWSY_x86_64-unknown-netbsd :=
|
||||
CFG_UNIXY_x86_64-unknown-netbsd := 1
|
||||
CFG_LDPATH_x86_64-unknown-netbsd :=
|
||||
CFG_RUN_x86_64-unknown-netbsd=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-netbsd=$(call CFG_RUN_x86_64-unknown-netbsd,,$(2))
|
||||
CFG_GNU_TRIPLE_x86_64-unknown-netbsd := x86_64-unknown-netbsd
|
@ -295,7 +295,6 @@ LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
|
||||
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
|
||||
LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir)
|
||||
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))"
|
||||
LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS))
|
||||
LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
|
||||
ifeq ($$(findstring freebsd,$(1)),freebsd)
|
||||
# On FreeBSD, it may search wrong headers (that are for pre-installed LLVM),
|
||||
|
@ -238,3 +238,56 @@ endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))
|
||||
|
||||
# There are more comments about this available in the target specification for
|
||||
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
|
||||
# instead of `lib.exe` for assembling archives, so we need to inject this custom
|
||||
# dependency here.
|
||||
define ADD_LLVM_AR_TO_MSVC_DEPS
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe
|
||||
INSTALLED_BINS_$(1) += llvm-ar.exe
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target))))
|
||||
|
||||
# When working with MSVC on windows, each DLL needs to explicitly declare its
|
||||
# interface to the outside world through some means. The options for doing so
|
||||
# include:
|
||||
#
|
||||
# 1. A custom attribute on each function itself
|
||||
# 2. A linker argument saying what to export
|
||||
# 3. A file which lists all symbols that need to be exported
|
||||
#
|
||||
# The Rust compiler takes care (1) for us for all Rust code by annotating all
|
||||
# public-facing functions with dllexport, but we have a few native dependencies
|
||||
# which need to cross the DLL boundary. The most important of these dependencies
|
||||
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
|
||||
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
|
||||
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
|
||||
#
|
||||
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
|
||||
# Windows for us, so we're forced to do it ourselves if we want it (which seems
|
||||
# like the path of least resistance right now). To do this we generate a `.DEF`
|
||||
# file [1] which we then custom-pass to the linker when building the rustc_llvm
|
||||
# crate. This DEF file list all symbols that are exported from
|
||||
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
|
||||
#
|
||||
# Fun times!
|
||||
#
|
||||
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
|
||||
define ADD_RUSTC_LLVM_DEF_TO_MSVC
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
RUSTFLAGS_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def"
|
||||
CUSTOM_DEPS_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def
|
||||
|
||||
$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs
|
||||
$$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))
|
||||
|
||||
|
28
mk/rt.mk
28
mk/rt.mk
@ -53,9 +53,7 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
|
||||
NATIVE_DEPS_miniz_$(1) = miniz.c
|
||||
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
|
||||
rust_android_dummy.c
|
||||
NATIVE_DEPS_rustrt_native_$(1) := \
|
||||
rust_try.ll \
|
||||
arch/$$(HOST_$(1))/record_sp.S
|
||||
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
|
||||
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
|
||||
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
|
||||
|
||||
@ -69,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
|
||||
|
||||
RT_OUTPUT_DIR_$(1) := $(1)/rt
|
||||
|
||||
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
|
||||
$$(LLVM_CONFIG_$$(CFG_BUILD))
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
|
||||
-filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
|
||||
-relocation-model=pic -o $$@ $$<
|
||||
|
||||
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
@ -90,6 +80,17 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
|
||||
|
||||
# On MSVC targets the compiler's default include path (e.g. where to find system
|
||||
# headers) is specified by the INCLUDE environment variable. This may not be set
|
||||
# so the ./configure script scraped the relevant values and this is the location
|
||||
# that we put them into cl.exe's environment.
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
$$(RT_OUTPUT_DIR_$(1))/%.o: \
|
||||
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
|
||||
$(1)/rustllvm/%.o: \
|
||||
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target))))
|
||||
@ -104,7 +105,6 @@ define THIRD_PARTY_LIB
|
||||
OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
|
||||
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
|
||||
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
|
||||
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
|
||||
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
|
||||
NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
|
||||
$$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
|
||||
@ -237,8 +237,12 @@ COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1))
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
COMPRT_CC_$(1) := gcc
|
||||
COMPRT_AR_$(1) := ar
|
||||
ifeq ($$(findstring i686,$(1)),i686)
|
||||
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32
|
||||
else
|
||||
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64
|
||||
endif
|
||||
endif
|
||||
|
||||
$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
|
||||
@$$(call E, make: compiler-rt)
|
||||
|
@ -24,7 +24,8 @@ LLVM_EXTRA_INCDIRS_$(1)= $$(call CFG_CC_INCLUDE_$(1),$(S)src/llvm/include) \
|
||||
endif
|
||||
|
||||
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
|
||||
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
|
||||
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp \
|
||||
ArchiveWrapper.cpp)
|
||||
|
||||
RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \
|
||||
$$(call CFG_CC_INCLUDE_$(1),$$(LLVM_INCDIR_$(1))) \
|
||||
|
35
mk/target.mk
35
mk/target.mk
@ -220,3 +220,38 @@ $(foreach target,$(CFG_TARGET), \
|
||||
$(foreach crate,$(CRATES), \
|
||||
$(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
|
||||
$(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))
|
||||
|
||||
# For MSVC targets we need to set up some environment variables for the linker
|
||||
# to work correctly when building Rust crates. These two variables are:
|
||||
#
|
||||
# - LIB tells the linker the default search path for finding system libraries,
|
||||
# for example kernel32.dll
|
||||
# - PATH needs to be modified to ensure that MSVC's link.exe is first in the
|
||||
# path instead of MinGW's /usr/bin/link.exe (entirely unrelated)
|
||||
#
|
||||
# The values for these variables are detected by the configure script.
|
||||
define SETUP_LIB_MSVC_ENV_VARS
|
||||
ifeq ($$(findstring msvc,$(2)),msvc)
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
|
||||
endif
|
||||
endef
|
||||
define SETUP_TOOL_MSVC_ENV_VARS
|
||||
ifeq ($$(findstring msvc,$(2)),msvc)
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach crate,$(CRATES), \
|
||||
$(eval $(call SETUP_LIB_MSVC_ENV_VARS,0,$(target),$(host),$(crate))))))
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach tool,$(TOOLS), \
|
||||
$(eval $(call SETUP_TOOL_MSVC_ENV_VARS,0,$(target),$(host),$(tool))))))
|
||||
|
@ -15,7 +15,7 @@
|
||||
#![feature(libc)]
|
||||
#![feature(path_ext)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(slice_extras)]
|
||||
#![feature(slice_splits)]
|
||||
#![feature(str_char)]
|
||||
#![feature(test)]
|
||||
#![feature(vec_push_all)]
|
||||
@ -90,9 +90,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"),
|
||||
optflag("h", "help", "show this message"));
|
||||
|
||||
assert!(!args.is_empty());
|
||||
let argv0 = args[0].clone();
|
||||
let args_ = args.tail();
|
||||
let (argv0, args_) = args.split_first().unwrap();
|
||||
if args[1] == "-h" || args[1] == "--help" {
|
||||
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
|
||||
println!("{}", getopts::usage(&message, &groups));
|
||||
|
@ -344,7 +344,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
check_lines,
|
||||
breakpoint_lines
|
||||
} = parse_debugger_commands(testfile, "gdb");
|
||||
let mut cmds = commands.connect("\n");
|
||||
let mut cmds = commands.join("\n");
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
let compiler_run_result = compile_test(config, props, testfile);
|
||||
@ -799,7 +799,7 @@ fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
|
||||
split_maybe_args(options).into_iter()
|
||||
.filter(|x| !options_to_remove.contains(x))
|
||||
.collect::<Vec<String>>()
|
||||
.connect(" ");
|
||||
.join(" ");
|
||||
Some(new_options)
|
||||
}
|
||||
|
||||
@ -1126,16 +1126,10 @@ impl fmt::Display for Status {
|
||||
|
||||
fn compile_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
compile_test_(config, props, testfile, &[])
|
||||
}
|
||||
|
||||
fn compile_test_(config: &Config, props: &TestProps,
|
||||
testfile: &Path, extra_args: &[String]) -> ProcRes {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut link_args = vec!("-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
link_args.extend(extra_args.iter().cloned());
|
||||
let link_args = vec!("-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
let args = make_compile_args(config,
|
||||
props,
|
||||
link_args,
|
||||
@ -1144,7 +1138,7 @@ fn compile_test_(config: &Config, props: &TestProps,
|
||||
}
|
||||
|
||||
fn document(config: &Config, props: &TestProps,
|
||||
testfile: &Path, extra_args: &[String]) -> (ProcRes, PathBuf) {
|
||||
testfile: &Path) -> (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);
|
||||
@ -1154,7 +1148,6 @@ fn document(config: &Config, props: &TestProps,
|
||||
"-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));
|
||||
let args = ProcArgs {
|
||||
prog: config.rustdoc_path.to_str().unwrap().to_string(),
|
||||
@ -1419,7 +1412,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
|
||||
|
||||
// Linux and mac don't require adjusting the library search path
|
||||
if cfg!(unix) {
|
||||
format!("{} {}", prog, args.connect(" "))
|
||||
format!("{} {}", prog, args.join(" "))
|
||||
} else {
|
||||
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
|
||||
// for diagnostic purposes
|
||||
@ -1427,7 +1420,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
|
||||
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
|
||||
}
|
||||
|
||||
format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" "))
|
||||
format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1709,15 +1702,18 @@ fn run_codegen_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
}
|
||||
|
||||
fn charset() -> &'static str {
|
||||
if cfg!(any(target_os = "bitrig", target_os = "freebsd")) {
|
||||
// FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
|
||||
if cfg!(target_os = "bitrig") {
|
||||
"auto"
|
||||
} else if cfg!(target_os = "freebsd") {
|
||||
"ISO-8859-1"
|
||||
} else {
|
||||
"UTF-8"
|
||||
}
|
||||
}
|
||||
|
||||
fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let (proc_res, out_dir) = document(config, props, testfile, &[]);
|
||||
let (proc_res, out_dir) = document(config, props, testfile);
|
||||
if !proc_res.status.success() {
|
||||
fatal_proc_rec("rustdoc failed!", &proc_res);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[
|
||||
("ios", "ios"),
|
||||
("linux", "linux"),
|
||||
("mingw32", "windows"),
|
||||
("netbsd", "netbsd"),
|
||||
("openbsd", "openbsd"),
|
||||
("win32", "windows"),
|
||||
("windows", "windows"),
|
||||
|
@ -99,7 +99,7 @@ Second, it makes cost explicit. In general, the only safe way to have a
|
||||
non-exhaustive match would be to panic the thread if nothing is matched, though
|
||||
it could fall through if the type of the `match` expression is `()`. This sort
|
||||
of hidden cost and special casing is against the language's philosophy. It's
|
||||
easy to ignore certain cases by using the `_` wildcard:
|
||||
easy to ignore all unspecified cases by using the `_` wildcard:
|
||||
|
||||
```rust,ignore
|
||||
match val.do_something() {
|
||||
|
@ -1,4 +1,7 @@
|
||||
% The (old) Rust Pointer Guide
|
||||
% The Rust Pointer Guide
|
||||
|
||||
This content has moved into
|
||||
[the Rust Programming Language book](book/pointers.html).
|
||||
This content has been removed, with no direct replacement. Rust only
|
||||
has two built-in pointer types now,
|
||||
[references](book/references-and-borrowing.html) and [raw
|
||||
pointers](book/raw-pointers.html). Older Rusts had many more pointer
|
||||
types, they’re gone now.
|
||||
|
@ -20,6 +20,13 @@ series of small examples.
|
||||
|
||||
[rbe]: http://rustbyexample.com/
|
||||
|
||||
# The Standard Library
|
||||
|
||||
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.
|
||||
|
||||
# Community & Getting Help
|
||||
|
||||
If you need help with something, or just want to talk about Rust with others,
|
||||
@ -75,13 +82,6 @@ There are questions that are asked quite often, so we've made FAQs for them:
|
||||
* [Project FAQ](complement-project-faq.html)
|
||||
* [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports)
|
||||
|
||||
# The Standard Library
|
||||
|
||||
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.
|
||||
|
||||
# The Error Index
|
||||
|
||||
If you encounter an error while compiling your code you may be able to look it
|
||||
|
@ -338,12 +338,16 @@ type of the literal. The integer suffix must be the name of one of the
|
||||
integral types: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`,
|
||||
`isize`, or `usize`.
|
||||
|
||||
The type of an _unsuffixed_ integer literal is determined by type inference.
|
||||
If an integer type can be _uniquely_ determined from the surrounding program
|
||||
context, the unsuffixed integer literal has that type. If the program context
|
||||
underconstrains the type, it defaults to the signed 32-bit integer `i32`; if
|
||||
the program context overconstrains the type, it is considered a static type
|
||||
error.
|
||||
The type of an _unsuffixed_ integer literal is determined by type inference:
|
||||
|
||||
* If an integer type can be _uniquely_ determined from the surrounding
|
||||
program context, the unsuffixed integer literal has that type.
|
||||
|
||||
* If the program context under-constrains the type, it defaults to the
|
||||
signed 32-bit integer `i32`.
|
||||
|
||||
* If the program context over-constrains the type, it is considered a
|
||||
static type error.
|
||||
|
||||
Examples of integer literals of various forms:
|
||||
|
||||
@ -371,12 +375,17 @@ The suffix forcibly sets the type of the literal. There are two valid
|
||||
_floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point
|
||||
types), which explicitly determine the type of the literal.
|
||||
|
||||
The type of an _unsuffixed_ floating-point literal is determined by type
|
||||
inference. If a floating-point type can be _uniquely_ determined from the
|
||||
surrounding program context, the unsuffixed floating-point literal has that type.
|
||||
If the program context underconstrains the type, it defaults to double-precision `f64`;
|
||||
if the program context overconstrains the type, it is considered a static type
|
||||
error.
|
||||
The type of an _unsuffixed_ floating-point literal is determined by
|
||||
type inference:
|
||||
|
||||
* If a floating-point type can be _uniquely_ determined from the
|
||||
surrounding program context, the unsuffixed floating-point literal
|
||||
has that type.
|
||||
|
||||
* If the program context under-constrains the type, it defaults to `f64`.
|
||||
|
||||
* If the program context over-constrains the type, it is considered a
|
||||
static type error.
|
||||
|
||||
Examples of floating-point literals of various forms:
|
||||
|
||||
@ -582,8 +591,9 @@ always been designed to be compiled. For these reasons, this section assumes a
|
||||
compiler.
|
||||
|
||||
Rust's semantics obey a *phase distinction* between compile-time and
|
||||
run-time.[^phase-distinction] Those semantic rules that have a *static
|
||||
interpretation* govern the success or failure of compilation. Those semantics
|
||||
run-time.[^phase-distinction] Semantic rules that have a *static
|
||||
interpretation* govern the success or failure of compilation, while
|
||||
semantic rules
|
||||
that have a *dynamic interpretation* govern the behavior of the program at
|
||||
run-time.
|
||||
|
||||
@ -1047,11 +1057,8 @@ This is a list of behavior not considered *unsafe* in Rust terms, but that may
|
||||
be undesired.
|
||||
|
||||
* Deadlocks
|
||||
* Reading data from private fields (`std::repr`)
|
||||
* Leaks of memory and other resources
|
||||
* Exiting without calling destructors
|
||||
* Sending signals
|
||||
* Accessing/modifying the file system
|
||||
* Integer overflow
|
||||
- Overflow is considered "unexpected" behavior and is always user-error,
|
||||
unless the `wrapping` primitives are used. In non-optimized builds, the compiler
|
||||
@ -1286,7 +1293,7 @@ All access to a static is safe, but there are a number of restrictions on
|
||||
statics:
|
||||
|
||||
* Statics may not contain any destructors.
|
||||
* The types of static values must ascribe to `Sync` to allow threadsafe access.
|
||||
* The types of static values must ascribe to `Sync` to allow thread-safe access.
|
||||
* Statics may not refer to other statics by value, only by reference.
|
||||
* Constants cannot refer to statics.
|
||||
|
||||
@ -1630,6 +1637,10 @@ The type of a function declared in an extern block is `extern "abi" fn(A1, ...,
|
||||
An) -> R`, where `A1...An` are the declared types of its arguments and `R` is
|
||||
the declared return type.
|
||||
|
||||
It is valid to add the `link` attribute on an empty extern block. You can use
|
||||
this to satisfy the linking requirements of extern blocks elsewhere in your code
|
||||
(including upstream crates) instead of adding the attribute to each extern block.
|
||||
|
||||
## Visibility and Privacy
|
||||
|
||||
These two terms are often used interchangeably, and what they are attempting to
|
||||
@ -1688,7 +1699,7 @@ explain, here's a few use cases and what they would entail:
|
||||
* A crate needs a global available "helper module" to itself, but it doesn't
|
||||
want to expose the helper module as a public API. To accomplish this, the
|
||||
root of the crate's hierarchy would have a private module which then
|
||||
internally has a "public api". Because the entire crate is a descendant of
|
||||
internally has a "public API". Because the entire crate is a descendant of
|
||||
the root, then the entire local crate can access this private module through
|
||||
the second case.
|
||||
|
||||
@ -1951,8 +1962,6 @@ macro scope.
|
||||
object file that this item's contents will be placed into.
|
||||
- `no_mangle` - on any item, do not apply the standard name mangling. Set the
|
||||
symbol for this item to its identifier.
|
||||
- `packed` - on structs or enums, eliminate any padding that would be used to
|
||||
align fields.
|
||||
- `simd` - on certain tuple structs, derive the arithmetic operators, which
|
||||
lower to the target's SIMD instructions, if any; the `simd` feature gate
|
||||
is necessary to use this attribute.
|
||||
@ -2026,7 +2035,7 @@ The following configurations must be defined by the implementation:
|
||||
as a configuration itself, like `unix` or `windows`.
|
||||
* `target_os = "..."`. Operating system of the target, examples include
|
||||
`"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
|
||||
`"bitrig"` or `"openbsd"`.
|
||||
`"bitrig"` , `"openbsd"` or `"netbsd"`.
|
||||
* `target_pointer_width = "..."`. Target pointer width in bits. This is set
|
||||
to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
|
||||
64-bit pointers.
|
||||
@ -2360,6 +2369,8 @@ The currently implemented features of the reference compiler are:
|
||||
internally without imposing on callers
|
||||
(i.e. making them behave like function calls in
|
||||
terms of encapsulation).
|
||||
* - `default_type_parameter_fallback` - Allows type parameter defaults to
|
||||
influence type inference.
|
||||
|
||||
If a feature is promoted to a language feature, then all existing programs will
|
||||
start to receive compilation warnings about `#![feature]` directives which enabled
|
||||
@ -2509,9 +2520,8 @@ Here are some examples:
|
||||
#### Moved and copied types
|
||||
|
||||
When a [local variable](#variables) is used as an
|
||||
[rvalue](#lvalues,-rvalues-and-temporaries) the variable will either be moved
|
||||
or copied, depending on its type. All values whose type implements `Copy` are
|
||||
copied, all others are moved.
|
||||
[rvalue](#lvalues,-rvalues-and-temporaries), the variable will be copied
|
||||
if its type implements `Copy`. All others are moved.
|
||||
|
||||
### Literal expressions
|
||||
|
||||
@ -2876,7 +2886,6 @@ operand.
|
||||
```
|
||||
# let mut x = 0;
|
||||
# let y = 0;
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
@ -2966,14 +2975,12 @@ move values (depending on their type) from the environment into the lambda
|
||||
expression's captured environment.
|
||||
|
||||
In this example, we define a function `ten_times` that takes a higher-order
|
||||
function argument, and call it with a lambda expression as an argument:
|
||||
function argument, and we then call it with a lambda expression as an argument:
|
||||
|
||||
```
|
||||
fn ten_times<F>(f: F) where F: Fn(i32) {
|
||||
let mut i = 0i32;
|
||||
while i < 10 {
|
||||
f(i);
|
||||
i += 1;
|
||||
for index in 0..10 {
|
||||
f(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3322,10 +3329,13 @@ An example of a tuple type and its use:
|
||||
|
||||
```
|
||||
type Pair<'a> = (i32, &'a str);
|
||||
let p: Pair<'static> = (10, "hello");
|
||||
let p: Pair<'static> = (10, "ten");
|
||||
let (a, b) = p;
|
||||
assert!(b != "world");
|
||||
assert!(p.0 == 10);
|
||||
|
||||
assert_eq!(a, 10);
|
||||
assert_eq!(b, "ten");
|
||||
assert_eq!(p.0, 10);
|
||||
assert_eq!(p.1, "ten");
|
||||
```
|
||||
|
||||
For historical reasons and convenience, the tuple type with no elements (`()`)
|
||||
@ -3335,8 +3345,8 @@ is often called ‘unit’ or ‘the unit type’.
|
||||
|
||||
Rust has two different types for a list of items:
|
||||
|
||||
* `[T; N]`, an 'array'.
|
||||
* `&[T]`, a 'slice'.
|
||||
* `[T; N]`, an 'array'
|
||||
* `&[T]`, a 'slice'
|
||||
|
||||
An array has a fixed size, and can be allocated on either the stack or the
|
||||
heap.
|
||||
@ -3344,18 +3354,23 @@ heap.
|
||||
A slice is a 'view' into an array. It doesn't own the data it points
|
||||
to, it borrows it.
|
||||
|
||||
An example of each kind:
|
||||
Examples:
|
||||
|
||||
```{rust}
|
||||
let vec: Vec<i32> = vec![1, 2, 3];
|
||||
let arr: [i32; 3] = [1, 2, 3];
|
||||
let s: &[i32] = &vec[..];
|
||||
// A stack-allocated array
|
||||
let array: [i32; 3] = [1, 2, 3];
|
||||
|
||||
// A heap-allocated array
|
||||
let vector: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
// A slice into an array
|
||||
let slice: &[i32] = &vector[..];
|
||||
```
|
||||
|
||||
As you can see, the `vec!` macro allows you to create a `Vec<T>` easily. The
|
||||
`vec!` macro is also part of the standard library, rather than the language.
|
||||
|
||||
All in-bounds elements of arrays, and slices are always initialized, and access
|
||||
All in-bounds elements of arrays and slices are always initialized, and access
|
||||
to an array or slice is always bounds-checked.
|
||||
|
||||
### Structure types
|
||||
@ -3489,7 +3504,7 @@ x = bo(5,7);
|
||||
|
||||
#### Function types for specific items
|
||||
|
||||
Internally to the compiler, there are also function types that are specific to a particular
|
||||
Internal to the compiler, there are also function types that are specific to a particular
|
||||
function item. In the following snippet, for example, the internal types of the functions
|
||||
`foo` and `bar` are different, despite the fact that they have the same signature:
|
||||
|
||||
@ -3517,13 +3532,14 @@ more of the closure traits:
|
||||
|
||||
* `FnMut`
|
||||
: The closure can be called multiple times as mutable. A closure called as
|
||||
`FnMut` can mutate values from its environment. `FnMut` implies
|
||||
`FnOnce`.
|
||||
`FnMut` can mutate values from its environment. `FnMut` inherits from
|
||||
`FnOnce` (i.e. anything implementing `FnMut` also implements `FnOnce`).
|
||||
|
||||
* `Fn`
|
||||
: The closure can be called multiple times through a shared reference.
|
||||
A closure called as `Fn` can neither move out from nor mutate values
|
||||
from its environment. `Fn` implies `FnMut` and `FnOnce`.
|
||||
from its environment. `Fn` inherits from `FnMut`, which itself
|
||||
inherits from `FnOnce`.
|
||||
|
||||
|
||||
### Trait objects
|
||||
@ -3646,53 +3662,77 @@ Coercions are defined in [RFC401]. A coercion is implicit and has no syntax.
|
||||
### Coercion sites
|
||||
|
||||
A coercion can only occur at certain coercion sites in a program; these are
|
||||
typically places where the desired type is explicit or can be dervied by
|
||||
typically places where the desired type is explicit or can be derived by
|
||||
propagation from explicit types (without type inference). Possible coercion
|
||||
sites are:
|
||||
|
||||
* `let` statements where an explicit type is given.
|
||||
|
||||
In `let _: U = e;`, `e` is coerced to have type `U`.
|
||||
For example, `128` is coerced to have type `i8` in the following:
|
||||
|
||||
```rust
|
||||
let _: i8 = 128;
|
||||
```
|
||||
|
||||
* `static` and `const` statements (similar to `let` statements).
|
||||
|
||||
* arguments for function calls.
|
||||
* Arguments for function calls
|
||||
|
||||
The value being coerced is the
|
||||
actual parameter and it is coerced to the type of the formal parameter. For
|
||||
example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as
|
||||
`foo(e);`. Then `e` is coerced to have type `U`;
|
||||
The value being coerced is the actual parameter, and it is coerced to
|
||||
the type of the formal parameter.
|
||||
|
||||
* instantiations of struct or variant fields.
|
||||
For example, `128` is coerced to have type `i8` in the following:
|
||||
|
||||
Assume we have a `struct
|
||||
Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to
|
||||
have type `U`.
|
||||
```rust
|
||||
fn bar(_: i8) { }
|
||||
|
||||
* function results (either the final line of a block if it is not semicolon
|
||||
terminated or any expression in a `return` statement).
|
||||
fn main() {
|
||||
bar(128);
|
||||
}
|
||||
```
|
||||
|
||||
In `fn foo() -> U { e }`, `e` is coerced to to have type `U`.
|
||||
* Instantiations of struct or variant fields
|
||||
|
||||
For example, `128` is coerced to have type `i8` in the following:
|
||||
|
||||
```rust
|
||||
struct Foo { x: i8 }
|
||||
|
||||
fn main() {
|
||||
Foo { x: 128 };
|
||||
}
|
||||
```
|
||||
|
||||
* Function results, either the final line of a block if it is not
|
||||
semicolon-terminated or any expression in a `return` statement
|
||||
|
||||
For example, `128` is coerced to have type `i8` in the following:
|
||||
|
||||
```rust
|
||||
fn foo() -> i8 {
|
||||
128
|
||||
}
|
||||
```
|
||||
|
||||
If the expression in one of these coercion sites is a coercion-propagating
|
||||
expression, then the relevant sub-expressions in that expression are also
|
||||
coercion sites. Propagation recurses from these new coercion sites.
|
||||
Propagating expressions and their relevant sub-expressions are:
|
||||
|
||||
* array literals, where the array has type `[U; n]`. Each sub-expression in
|
||||
* Array literals, where the array has type `[U; n]`. Each sub-expression in
|
||||
the array literal is a coercion site for coercion to type `U`.
|
||||
|
||||
* array literals with repeating syntax, where the array has type `[U; n]`. The
|
||||
* Array literals with repeating syntax, where the array has type `[U; n]`. The
|
||||
repeated sub-expression is a coercion site for coercion to type `U`.
|
||||
|
||||
* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`.
|
||||
* Tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`.
|
||||
Each sub-expression is a coercion site to the respective type, e.g. the
|
||||
zeroth sub-expression is a coercion site to type `U_0`.
|
||||
|
||||
* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then
|
||||
* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then
|
||||
the sub-expression is a coercion site to `U`.
|
||||
|
||||
* blocks. If a block has type `U`, then the last expression in the block (if
|
||||
* Blocks: if a block has type `U`, then the last expression in the block (if
|
||||
it is not semicolon-terminated) is a coercion site to `U`. This includes
|
||||
blocks which are part of control flow statements, such as `if`/`else`, if
|
||||
the block has a known type.
|
||||
@ -3701,45 +3741,46 @@ the block has a known type.
|
||||
|
||||
Coercion is allowed between the following types:
|
||||
|
||||
* `T` to `U` if `T` is a subtype of `U` (*reflexive case*).
|
||||
* `T` to `U` if `T` is a subtype of `U` (*reflexive case*)
|
||||
|
||||
* `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
|
||||
(*transitive case*).
|
||||
(*transitive case*)
|
||||
|
||||
Note that this is not fully supported yet
|
||||
|
||||
* `&mut T` to `&T`.
|
||||
* `&mut T` to `&T`
|
||||
|
||||
* `*mut T` to `*const T`.
|
||||
* `*mut T` to `*const T`
|
||||
|
||||
* `&T` to `*const T`.
|
||||
* `&T` to `*const T`
|
||||
|
||||
* `&mut T` to `*mut T`.
|
||||
* `&mut T` to `*mut T`
|
||||
|
||||
* `&T` to `&U` if `T` implements `Deref<Target = U>`. For example:
|
||||
|
||||
```rust
|
||||
use std::ops::Deref;
|
||||
```rust
|
||||
use std::ops::Deref;
|
||||
|
||||
struct CharContainer {
|
||||
value: char
|
||||
}
|
||||
struct CharContainer {
|
||||
value: char
|
||||
}
|
||||
|
||||
impl Deref for CharContainer {
|
||||
type Target = char;
|
||||
impl Deref for CharContainer {
|
||||
type Target = char;
|
||||
|
||||
fn deref<'a>(&'a self) -> &'a char {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
fn deref<'a>(&'a self) -> &'a char {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
fn foo(arg: &char) {}
|
||||
fn foo(arg: &char) {}
|
||||
|
||||
fn main() {
|
||||
let x = &mut CharContainer { value: 'y' };
|
||||
foo(x); //&mut CharContainer is coerced to &char.
|
||||
}
|
||||
```
|
||||
|
||||
fn main() {
|
||||
let x = &mut CharContainer { value: 'y' };
|
||||
foo(x); //&mut CharContainer is coerced to &char.
|
||||
}
|
||||
```
|
||||
* `&mut T` to `&mut U` if `T` implements `DerefMut<Target = U>`.
|
||||
|
||||
* TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of
|
||||
@ -3953,7 +3994,7 @@ In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for
|
||||
all compilation needs, and the other options are just available if more
|
||||
fine-grained control is desired over the output format of a Rust crate.
|
||||
|
||||
# Appendix: Rationales and design tradeoffs
|
||||
# Appendix: Rationales and design trade-offs
|
||||
|
||||
*TODO*.
|
||||
|
||||
@ -3963,7 +4004,7 @@ Rust is not a particularly original language, with design elements coming from
|
||||
a wide range of sources. Some of these are listed below (including elements
|
||||
that have since been removed):
|
||||
|
||||
* SML, OCaml: algebraic datatypes, pattern matching, type inference,
|
||||
* SML, OCaml: algebraic data types, pattern matching, type inference,
|
||||
semicolon statement separation
|
||||
* C++: references, RAII, smart pointers, move semantics, monomorphisation,
|
||||
memory model
|
||||
|
@ -221,6 +221,10 @@ a > code {
|
||||
color: #428BCA;
|
||||
}
|
||||
|
||||
.section-header > a > code {
|
||||
color: #8D1A38;
|
||||
}
|
||||
|
||||
/* Code highlighting */
|
||||
pre.rust .kw { color: #8959A8; }
|
||||
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
|
||||
|
@ -16,6 +16,7 @@
|
||||
* [Iterators](iterators.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [Choosing your Guarantees](choosing-your-guarantees.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Borrow and AsRef](borrow-and-asref.md)
|
||||
* [Release Channels](release-channels.md)
|
||||
@ -63,7 +64,7 @@
|
||||
* [No stdlib](no-stdlib.md)
|
||||
* [Intrinsics](intrinsics.md)
|
||||
* [Lang items](lang-items.md)
|
||||
* [Link args](link-args.md)
|
||||
* [Advanced linking](advanced-linking.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
|
||||
* [Slice Patterns](slice-patterns.md)
|
||||
|
@ -12,7 +12,7 @@ Recommended for inspiration and a better understanding of Rust's background.
|
||||
* [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)
|
||||
* [External uniqueness is unique enough](http://www.cs.uu.nl/research/techreps/UU-CS-2002-048.html)
|
||||
* [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)
|
||||
|
||||
@ -26,10 +26,10 @@ Recommended for inspiration and a better understanding of Rust's background.
|
||||
* [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)
|
||||
* [Scheduling techniques for concurrent systems](http://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.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)
|
||||
* [Three layer cake for shared-memory programming](http://dl.acm.org/citation.cfm?id=1953616&dl=ACM&coll=DL&CFID=524387192&CFTOKEN=44362705)
|
||||
* [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)
|
||||
|
151
src/doc/trpl/advanced-linking.md
Normal file
151
src/doc/trpl/advanced-linking.md
Normal file
@ -0,0 +1,151 @@
|
||||
% Advanced Linking
|
||||
|
||||
The common cases of linking with Rust have been covered earlier in this book,
|
||||
but supporting the range of linking possibilities made available by other
|
||||
languages is important for Rust to achieve seamless interaction with native
|
||||
libraries.
|
||||
|
||||
# Link args
|
||||
|
||||
There is one other way to tell `rustc` how to customize linking, and that is via
|
||||
the `link_args` attribute. This attribute is applied to `extern` blocks and
|
||||
specifies raw flags which need to get passed to the linker when producing an
|
||||
artifact. An example usage would be:
|
||||
|
||||
``` no_run
|
||||
#![feature(link_args)]
|
||||
|
||||
#[link_args = "-foo -bar -baz"]
|
||||
extern {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
||||
because this is not a sanctioned way of performing linking. Right now `rustc`
|
||||
shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
|
||||
so it makes sense to provide extra command line
|
||||
arguments, but this will not always be the case. In the future `rustc` may use
|
||||
LLVM directly to link native libraries, in which case `link_args` will have no
|
||||
meaning. You can achieve the same effect as the `link-args` attribute with the
|
||||
`-C link-args` argument to `rustc`.
|
||||
|
||||
It is highly recommended to *not* use this attribute, and rather use the more
|
||||
formal `#[link(...)]` attribute on `extern` blocks instead.
|
||||
|
||||
# Static linking
|
||||
|
||||
Static linking refers to the process of creating output that contain all
|
||||
required libraries and so don't need libraries installed on every system where
|
||||
you want to use your compiled project. Pure-Rust dependencies are statically
|
||||
linked by default so you can use created binaries and libraries without
|
||||
installing the Rust everywhere. By contrast, native libraries
|
||||
(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to
|
||||
change this and statically link them as well.
|
||||
|
||||
Linking is a very platform dependent topic — on some platforms, static linking
|
||||
may not be possible at all! This section assumes some basic familiarity with
|
||||
linking on your platform of choice.
|
||||
|
||||
## Linux
|
||||
|
||||
By default, all Rust programs on Linux will link to the system `libc` along with
|
||||
a number of other libraries. Let's look at an example on a 64-bit Linux machine
|
||||
with GCC and `glibc` (by far the most common `libc` on Linux):
|
||||
|
||||
``` text
|
||||
$ cat example.rs
|
||||
fn main() {}
|
||||
$ rustc example.rs
|
||||
$ ldd example
|
||||
linux-vdso.so.1 => (0x00007ffd565fd000)
|
||||
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
|
||||
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
|
||||
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
|
||||
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
|
||||
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
|
||||
/lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
|
||||
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)
|
||||
```
|
||||
|
||||
Dynamic linking on Linux can be undesirable if you wish to use new library
|
||||
features on old systems or target systems which do not have the required
|
||||
dependencies for your program to run.
|
||||
|
||||
Static linking is supported via an alternative `libc`, `musl` - this must be
|
||||
enabled at Rust compile-time with some prerequisites available. You can compile
|
||||
your own version of Rust with `musl` enabled and install it into a custom
|
||||
directory with the instructions below:
|
||||
|
||||
```text
|
||||
$ mkdir musldist
|
||||
$ PREFIX=$(pwd)/musldist
|
||||
$
|
||||
$ # Build musl
|
||||
$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
|
||||
[...]
|
||||
$ tar xf musl-1.1.10.tar.gz
|
||||
$ cd musl-1.1.10/
|
||||
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
|
||||
[...]
|
||||
musl-1.1.10 $ make
|
||||
[...]
|
||||
musl-1.1.10 $ make install
|
||||
[...]
|
||||
musl-1.1.10 $ cd ..
|
||||
$ du -h musldist/lib/libc.a
|
||||
2.2M musldist/lib/libc.a
|
||||
$
|
||||
$ # Build libunwind.a
|
||||
$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
|
||||
$ tar xf llvm-3.6.1.src.tar.xz
|
||||
$ cd llvm-3.6.1.src/projects/
|
||||
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
|
||||
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
|
||||
llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
|
||||
llvm-3.6.1.src/projects $ mkdir libunwind/build
|
||||
llvm-3.6.1.src/projects $ cd libunwind/build
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
|
||||
llvm-3.6.1.src/projects/libunwind/build $ make
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
|
||||
$ du -h musldist/lib/libunwind.a
|
||||
164K musldist/lib/libunwind.a
|
||||
$
|
||||
$ # Build musl-enabled rust
|
||||
$ git clone https://github.com/rust-lang/rust.git muslrust
|
||||
$ cd muslrust
|
||||
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
|
||||
muslrust $ make
|
||||
muslrust $ make install
|
||||
muslrust $ cd ..
|
||||
$ du -h musldist/bin/rustc
|
||||
12K musldist/bin/rustc
|
||||
```
|
||||
|
||||
You now have a build of a `musl`-enabled Rust! Because we've installed it to a
|
||||
custom prefix we need to make sure our system can the binaries and appropriate
|
||||
libraries when we try and run it:
|
||||
|
||||
```text
|
||||
$ export PATH=$PREFIX/bin:$PATH
|
||||
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
Let's try it out!
|
||||
|
||||
```text
|
||||
$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
|
||||
$ rustc --target=x86_64-unknown-linux-musl example.rs
|
||||
$ ldd example
|
||||
not a dynamic executable
|
||||
$ ./example
|
||||
hi!
|
||||
thread '<main>' panicked at 'failed', example.rs:1
|
||||
```
|
||||
|
||||
Success! This binary can be copied to almost any Linux machine with the same
|
||||
machine architecture and run without issues.
|
||||
|
||||
`cargo build` also permits the `--target` option so you should be able to build
|
||||
your crates as normal. However, you may need to recompile your native libraries
|
||||
against `musl` before they can be linked against.
|
356
src/doc/trpl/choosing-your-guarantees.md
Normal file
356
src/doc/trpl/choosing-your-guarantees.md
Normal file
@ -0,0 +1,356 @@
|
||||
% Choosing your Guarantees
|
||||
|
||||
One important feature of Rust as language is that it lets us control the costs and guarantees
|
||||
of a program.
|
||||
|
||||
There are various “wrapper type” abstractions in the Rust standard library which embody
|
||||
a multitude of tradeoffs between cost, ergonomics, and guarantees. Many let one choose between
|
||||
run time and compile time enforcement. This section will explain a few selected abstractions in
|
||||
detail.
|
||||
|
||||
Before proceeding, it is highly recommended that one reads about [ownership][ownership] and
|
||||
[borrowing][borrowing] in Rust.
|
||||
|
||||
[ownership]: ownership.html
|
||||
[borrowing]: references-and-borrowing.html
|
||||
|
||||
# Basic pointer types
|
||||
|
||||
## `Box<T>`
|
||||
|
||||
[`Box<T>`][box] is pointer which is “owned”, or a “box”. While it can hand
|
||||
out references to the contained data, it is the only owner of the data. In particular, when
|
||||
something like the following occurs:
|
||||
|
||||
```rust
|
||||
let x = Box::new(1);
|
||||
let y = x;
|
||||
// x no longer accessible here
|
||||
```
|
||||
|
||||
Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the
|
||||
programmer to use `x` after this. A box can similarly be moved _out_ of a function by returning it.
|
||||
|
||||
When a box (that hasn't been moved) goes out of scope, destructors are run. These destructors take
|
||||
care of deallocating the inner data.
|
||||
|
||||
This is a zero-cost abstraction for dynamic allocation. If you want to allocate some memory on the
|
||||
heap and safely pass around a pointer to that memory, this is ideal. Note that you will only be
|
||||
allowed to share references to this by the regular borrowing rules, checked at compile time.
|
||||
|
||||
[box]: ../std/boxed/struct.Box.html
|
||||
|
||||
## `&T` and `&mut T`
|
||||
|
||||
These are immutable and mutable references respectively. They follow the &lquo;read-write lock&rquo;
|
||||
pattern, such that one may either have only one mutable reference to some data, or any number of
|
||||
immutable ones, but not both. This guarantee is enforced at compile time, and has no visible cost at
|
||||
runtime. In most cases these two pointer types suffice for sharing cheap references between sections
|
||||
of code.
|
||||
|
||||
These pointers cannot be copied in such a way that they outlive the lifetime associated with them.
|
||||
|
||||
## `*const T` and `*mut T`
|
||||
|
||||
These are C-like raw pointers with no lifetime or ownership attached to them. They just point to
|
||||
some location in memory with no other restrictions. The only guarantee that these provide is that
|
||||
they cannot be dereferenced except in code marked `unsafe`.
|
||||
|
||||
These are useful when building safe, low cost abstractions like `Vec<T>`, but should be avoided in
|
||||
safe code.
|
||||
|
||||
## `Rc<T>`
|
||||
|
||||
This is the first wrapper we will cover that has a runtime cost.
|
||||
|
||||
[`Rc<T>`][rc] is a reference counted pointer. In other words, this lets us have multiple "owning"
|
||||
pointers to the same data, and the data will be dropped (destructors will be run) when all pointers
|
||||
are out of scope.
|
||||
|
||||
Internally, it contains a shared “reference count” (also called “refcount”),
|
||||
which is incremented each time the `Rc` is cloned, and decremented each time one of the `Rc`s goes
|
||||
out of scope. The main responsibility of `Rc<T>` is to ensure that destructors are called for shared
|
||||
data.
|
||||
|
||||
The internal data here is immutable, and if a cycle of references is created, the data will be
|
||||
leaked. If we want data that doesn't leak when there are cycles, we need a garbage collector.
|
||||
|
||||
#### Guarantees
|
||||
|
||||
The main guarantee provided here is that the data will not be destroyed until all references to it
|
||||
are out of scope.
|
||||
|
||||
This should be used when we wish to dynamically allocate and share some data (read-only) between
|
||||
various portions of yur program, where it is not certain which portion will finish using the pointer
|
||||
last. It's a viable alternative to `&T` when `&T` is either impossible to statically check for
|
||||
correctness, or creates extremely unergonomic code where the programmer does not wish to spend the
|
||||
development cost of working with.
|
||||
|
||||
This pointer is _not_ thread safe, and Rust will not let it be sent or shared with other threads.
|
||||
This lets one avoid the cost of atomics in situations where they are unnecessary.
|
||||
|
||||
There is a sister smart pointer to this one, `Weak<T>`. This is a non-owning, but also non-borrowed,
|
||||
smart pointer. It is also similar to `&T`, but it is not restricted in lifetime—a `Weak<T>`
|
||||
can be held on to forever. However, it is possible that an attempt to access the inner data may fail
|
||||
and return `None`, since this can outlive the owned `Rc`s. This is useful for cyclic
|
||||
data structures and other things.
|
||||
|
||||
#### Cost
|
||||
|
||||
As far as memory goes, `Rc<T>` is a single allocation, though it will allocate two extra words (i.e.
|
||||
two `usize` values) as compared to a regular `Box<T>` (for "strong" and "weak" refcounts).
|
||||
|
||||
`Rc<T>` has the computational cost of incrementing/decrementing the refcount whenever it is cloned
|
||||
or goes out of scope respectively. Note that a clone will not do a deep copy, rather it will simply
|
||||
increment the inner reference count and return a copy of the `Rc<T>`.
|
||||
|
||||
[rc]: ../std/rc/struct.Rc.html
|
||||
|
||||
# Cell types
|
||||
|
||||
&lquo;Cell&rquo;s provide interior mutability. In other words, they contain data which can be manipulated even
|
||||
if the type cannot be obtained in a mutable form (for example, when it is behind an `&`-ptr or
|
||||
`Rc<T>`).
|
||||
|
||||
[The documentation for the `cell` module has a pretty good explanation for these][cell-mod].
|
||||
|
||||
These types are _generally_ found in struct fields, but they may be found elsewhere too.
|
||||
|
||||
## `Cell<T>`
|
||||
|
||||
[`Cell<T>`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types.
|
||||
Since the compiler knows that all the data owned by the contained value is on the stack, there's
|
||||
no worry of leaking any data behind references (or worse!) by simply replacing the data.
|
||||
|
||||
It is still possible to violate your own invariants using this wrapper, so be careful when using it.
|
||||
If a field is wrapped in `Cell`, it's a nice indicator that the chunk of data is mutable and may not
|
||||
stay the same between the time you first read it and when you intend to use it.
|
||||
|
||||
```rust
|
||||
# use std::cell::Cell;
|
||||
let x = Cell::new(1);
|
||||
let y = &x;
|
||||
let z = &x;
|
||||
x.set(2);
|
||||
y.set(3);
|
||||
z.set(4);
|
||||
println!("{}", x.get());
|
||||
```
|
||||
|
||||
Note that here we were able to mutate the same value from various immutable references.
|
||||
|
||||
This has the same runtime cost as the following:
|
||||
|
||||
```rust,ignore
|
||||
let mut x = 1;
|
||||
let y = &mut x;
|
||||
let z = &mut x;
|
||||
x = 2;
|
||||
*y = 3;
|
||||
*z = 4;
|
||||
println!("{}", x);
|
||||
```
|
||||
|
||||
but it has the added benefit of actually compiling successfully.
|
||||
|
||||
#### Guarantees
|
||||
|
||||
This relaxes the “no aliasing with mutability” restriction in places where it's
|
||||
unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your
|
||||
invariants depend on data stored within `Cell`, you should be careful.
|
||||
|
||||
This is useful for mutating primitives and other `Copy` types when there is no easy way of
|
||||
doing it in line with the static rules of `&` and `&mut`.
|
||||
|
||||
`Cell` does not let you obtain interior references to the data, which makes it safe to freely
|
||||
mutate.
|
||||
|
||||
#### Cost
|
||||
|
||||
There is no runtime cost to using `Cell<T>`, however if you are using it to wrap larger (`Copy`)
|
||||
structs, it might be worthwhile to instead wrap individual fields in `Cell<T>` since each write is
|
||||
otherwise a full copy of the struct.
|
||||
|
||||
|
||||
## `RefCell<T>`
|
||||
|
||||
[`RefCell<T>`][refcell] also provides interior mutability, but isn't restricted to `Copy` types.
|
||||
|
||||
Instead, it has a runtime cost. `RefCell<T>` enforces the read-write lock pattern at runtime (it's
|
||||
like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the
|
||||
`borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart
|
||||
pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when
|
||||
the smart pointers go out of scope. With this system, we can dynamically ensure that there are never
|
||||
any other borrows active when a mutable borrow is active. If the programmer attempts to make such a
|
||||
borrow, the thread will panic.
|
||||
|
||||
```rust
|
||||
# use std::cell::RefCell;
|
||||
let x = RefCell::new(vec![1,2,3,4]);
|
||||
{
|
||||
println!("{:?}", *x.borrow())
|
||||
}
|
||||
|
||||
{
|
||||
let mut my_ref = x.borrow_mut();
|
||||
my_ref.push(1);
|
||||
}
|
||||
```
|
||||
|
||||
Similar to `Cell`, this is mainly useful for situations where it's hard or impossible to satisfy the
|
||||
borrow checker. Generally we know that such mutations won't happen in a nested form, but it's good
|
||||
to check.
|
||||
|
||||
For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things
|
||||
simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals
|
||||
are inside this wrapper. These are only modified once (during creation, which is not right after
|
||||
initialization) or a couple of times in well-separated places. However, since this struct is
|
||||
pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps
|
||||
impossible) and probably form a soup of `&`-ptrs which would be hard to extend. On the other hand,
|
||||
the `RefCell` provides a cheap (not zero-cost) way of safely accessing these. In the future, if
|
||||
someone adds some code that attempts to modify the cell when it's already borrowed, it will cause a
|
||||
(usually deterministic) panic which can be traced back to the offending borrow.
|
||||
|
||||
Similarly, in Servo's DOM there is a lot of mutation, most of which is local to a DOM type, but some
|
||||
of which crisscrosses the DOM and modifies various things. Using `RefCell` and `Cell` to guard all
|
||||
mutation lets us avoid worrying about mutability everywhere, and it simultaneously highlights the
|
||||
places where mutation is _actually_ happening.
|
||||
|
||||
Note that `RefCell` should be avoided if a mostly simple solution is possible with `&` pointers.
|
||||
|
||||
#### Guarantees
|
||||
|
||||
`RefCell` relaxes the _static_ restrictions preventing aliased mutation, and replaces them with
|
||||
_dynamic_ ones. As such the guarantees have not changed.
|
||||
|
||||
#### Cost
|
||||
|
||||
`RefCell` does not allocate, but it contains an additional "borrow state"
|
||||
indicator (one word in size) along with the data.
|
||||
|
||||
At runtime each borrow causes a modification/check of the refcount.
|
||||
|
||||
[cell-mod]: ../std/cell/
|
||||
[cell]: ../std/cell/struct.Cell.html
|
||||
[refcell]: ../std/cell/struct.RefCell.html
|
||||
[ctxt]: ../rustc/middle/ty/struct.ctxt.html
|
||||
|
||||
# Synchronous types
|
||||
|
||||
Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc<T>` and
|
||||
`RefCell<T>`, which both use non-atomic reference counts (_atomic_ reference counts are those which
|
||||
can be incremented from multiple threads without causing a data race), cannot be used this way. This
|
||||
makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of
|
||||
`Arc<T>` and `Mutex<T>`/`RWLock<T>`
|
||||
|
||||
Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile
|
||||
time.
|
||||
|
||||
There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the
|
||||
major ones will be covered below.
|
||||
|
||||
[sync]: ../std/sync/index.html
|
||||
|
||||
## `Arc<T>`
|
||||
|
||||
[`Arc<T>`][arc] is just a version of `Rc<T>` that uses an atomic reference count (hence, "Arc").
|
||||
This can be sent freely between threads.
|
||||
|
||||
C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable.
|
||||
For semantics similar to that from C++, we should use `Arc<Mutex<T>>`, `Arc<RwLock<T>>`, or
|
||||
`Arc<UnsafeCell<T>>`[^4] (`UnsafeCell<T>` is a cell type that can be used to hold any data and has
|
||||
no runtime cost, but accessing it requires `unsafe` blocks). The last one should only be used if we
|
||||
are certain that the usage won't cause any memory unsafety. Remember that writing to a struct is not
|
||||
an atomic operation, and many functions like `vec.push()` can reallocate internally and cause unsafe
|
||||
behavior, so even monotonicity may not be enough to justify `UnsafeCell`.
|
||||
|
||||
[^4]: `Arc<UnsafeCell<T>>` actually won't compile since `UnsafeCell<T>` isn't `Send` or `Sync`, but we can wrap it in a type and implement `Send`/`Sync` for it manually to get `Arc<Wrapper<T>>` where `Wrapper` is `struct Wrapper<T>(UnsafeCell<T>)`.
|
||||
|
||||
#### Guarantees
|
||||
|
||||
Like `Rc`, this provides the (thread safe) guarantee that the destructor for the internal data will
|
||||
be run when the last `Arc` goes out of scope (barring any cycles).
|
||||
|
||||
#### Cost
|
||||
|
||||
This has the added cost of using atomics for changing the refcount (which will happen whenever it is
|
||||
cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable
|
||||
to share `&` pointers whenever possible.
|
||||
|
||||
[arc]: ../std/sync/struct.Arc.html
|
||||
|
||||
## `Mutex<T>` and `RwLock<T>`
|
||||
|
||||
[`Mutex<T>`][mutex] and [`RwLock<T>`][rwlock] provide mutual-exclusion via RAII guards (guards are
|
||||
objects which maintain some state, like a lock, until their destructor is called). For both of
|
||||
these, the mutex is opaque until we call `lock()` on it, at which point the thread will block
|
||||
until a lock can be acquired, and then a guard will be returned. This guard can be used to access
|
||||
the inner data (mutably), and the lock will be released when the guard goes out of scope.
|
||||
|
||||
```rust,ignore
|
||||
{
|
||||
let guard = mutex.lock();
|
||||
// guard dereferences mutably to the inner type
|
||||
*guard += 1;
|
||||
} // lock released when destructor runs
|
||||
```
|
||||
|
||||
|
||||
`RwLock` has the added benefit of being efficient for multiple reads. It is always safe to have
|
||||
multiple readers to shared data as long as there are no writers; and `RwLock` lets readers acquire a
|
||||
"read lock". Such locks can be acquired concurrently and are kept track of via a reference count.
|
||||
Writers must obtain a "write lock" which can only be obtained when all readers have gone out of
|
||||
scope.
|
||||
|
||||
#### Guarantees
|
||||
|
||||
Both of these provide safe shared mutability across threads, however they are prone to deadlocks.
|
||||
Some level of additional protocol safety can be obtained via the type system.
|
||||
#### Costs
|
||||
|
||||
These use internal atomic-like types to maintain the locks, which are pretty costly (they can block
|
||||
all memory reads across processors till they're done). Waiting on these locks can also be slow when
|
||||
there's a lot of concurrent access happening.
|
||||
|
||||
[rwlock]: ../std/sync/struct.RwLock.html
|
||||
[mutex]: ../std/sync/struct.Mutex.html
|
||||
[sessions]: https://github.com/Munksgaard/rust-sessions
|
||||
|
||||
# Composition
|
||||
|
||||
A common gripe when reading Rust code is with types like `Rc<RefCell<Vec<T>>>` (or even more more
|
||||
complicated compositions of such types). It's not always clear what the composition does, or why the
|
||||
author chose one like this (and when one should be using such a composition in one's own code)
|
||||
|
||||
Usually, it's a case of composing together the guarantees that you need, without paying for stuff
|
||||
that is unnecessary.
|
||||
|
||||
For example, `Rc<RefCell<T>>` is one such composition. `Rc<T>` itself can't be dereferenced mutably;
|
||||
because `Rc<T>` provides sharing and shared mutability can lead to unsafe behavior, so we put
|
||||
`RefCell<T>` inside to get dynamically verified shared mutability. Now we have shared mutable data,
|
||||
but it's shared in a way that there can only be one mutator (and no readers) or multiple readers.
|
||||
|
||||
Now, we can take this a step further, and have `Rc<RefCell<Vec<T>>>` or `Rc<Vec<RefCell<T>>>`. These
|
||||
are both shareable, mutable vectors, but they're not the same.
|
||||
|
||||
With the former, the `RefCell<T>` is wrapping the `Vec<T>`, so the `Vec<T>` in its entirety is
|
||||
mutable. At the same time, there can only be one mutable borrow of the whole `Vec` at a given time.
|
||||
This means that your code cannot simultaneously work on different elements of the vector from
|
||||
different `Rc` handles. However, we are able to push and pop from the `Vec<T>` at will. This is
|
||||
similar to an `&mut Vec<T>` with the borrow checking done at runtime.
|
||||
|
||||
With the latter, the borrowing is of individual elements, but the overall vector is immutable. Thus,
|
||||
we can independently borrow separate elements, but we cannot push or pop from the vector. This is
|
||||
similar to an `&mut [T]`[^3], but, again, the borrow checking is at runtime.
|
||||
|
||||
In concurrent programs, we have a similar situation with `Arc<Mutex<T>>`, which provides shared
|
||||
mutability and ownership.
|
||||
|
||||
When reading code that uses these, go in step by step and look at the guarantees/costs provided.
|
||||
|
||||
When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at
|
||||
which point of the composition we need them. For example, if there is a choice between
|
||||
`Vec<RefCell<T>>` and `RefCell<Vec<T>>`, we should figure out the tradeoffs as done above and pick
|
||||
one.
|
||||
|
||||
[^3]: `&[T]` and `&mut [T]` are _slices_; they consist of a pointer and a length and can refer to a portion of a vector or array. `&mut [T]` can have its elements mutated, however its length cannot be touched.
|
@ -38,6 +38,17 @@ fn add_one(x: i32) -> i32 {
|
||||
}
|
||||
```
|
||||
|
||||
There is another style of doc comment, `//!`, to comment containing items (e.g.
|
||||
crates, modules or functions), instead of the items following it. Commonly used
|
||||
inside crates root (lib.rs) or modules root (mod.rs):
|
||||
|
||||
```
|
||||
//! # The Rust Standard Library
|
||||
//!
|
||||
//! The Rust Standard Library provides the essential runtime
|
||||
//! functionality for building portable Rust software.
|
||||
```
|
||||
|
||||
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
|
||||
|
@ -10,11 +10,12 @@ system is up to the task, and gives you powerful ways to reason about
|
||||
concurrent code at compile time.
|
||||
|
||||
Before we talk about the concurrency features that come with Rust, it's important
|
||||
to understand something: Rust is low-level enough that all of this is provided
|
||||
by the standard library, not by the language. This means that if you don't like
|
||||
some aspect of the way Rust handles concurrency, you can implement an alternative
|
||||
way of doing things. [mio](https://github.com/carllerche/mio) is a real-world
|
||||
example of this principle in action.
|
||||
to understand something: Rust is low-level enough that the vast majority of
|
||||
this is provided by the standard library, not by the language. This means that
|
||||
if you don't like some aspect of the way Rust handles concurrency, you can
|
||||
implement an alternative way of doing things.
|
||||
[mio](https://github.com/carllerche/mio) is a real-world example of this
|
||||
principle in action.
|
||||
|
||||
## Background: `Send` and `Sync`
|
||||
|
||||
|
@ -151,7 +151,7 @@ look at `main()` again:
|
||||
# struct Philosopher {
|
||||
# name: String,
|
||||
# }
|
||||
#
|
||||
#
|
||||
# impl Philosopher {
|
||||
# fn new(name: &str) -> Philosopher {
|
||||
# Philosopher {
|
||||
@ -159,7 +159,7 @@ look at `main()` again:
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
#
|
||||
fn main() {
|
||||
let p1 = Philosopher::new("Judith Butler");
|
||||
let p2 = Philosopher::new("Gilles Deleuze");
|
||||
@ -197,15 +197,15 @@ a method, and then loop through all the philosophers, calling it:
|
||||
```rust
|
||||
struct Philosopher {
|
||||
name: String,
|
||||
}
|
||||
}
|
||||
|
||||
impl Philosopher {
|
||||
impl Philosopher {
|
||||
fn new(name: &str) -> Philosopher {
|
||||
Philosopher {
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn eat(&self) {
|
||||
println!("{} is done eating.", self.name);
|
||||
}
|
||||
@ -267,15 +267,15 @@ use std::thread;
|
||||
|
||||
struct Philosopher {
|
||||
name: String,
|
||||
}
|
||||
}
|
||||
|
||||
impl Philosopher {
|
||||
impl Philosopher {
|
||||
fn new(name: &str) -> Philosopher {
|
||||
Philosopher {
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn eat(&self) {
|
||||
println!("{} is eating.", self.name);
|
||||
|
||||
@ -348,9 +348,9 @@ use std::thread;
|
||||
|
||||
struct Philosopher {
|
||||
name: String,
|
||||
}
|
||||
}
|
||||
|
||||
impl Philosopher {
|
||||
impl Philosopher {
|
||||
fn new(name: &str) -> Philosopher {
|
||||
Philosopher {
|
||||
name: name.to_string(),
|
||||
@ -401,7 +401,7 @@ let handles: Vec<_> = philosophers.into_iter().map(|p| {
|
||||
While this is only five lines, they’re a dense five. Let’s break it down.
|
||||
|
||||
```rust,ignore
|
||||
let handles: Vec<_> =
|
||||
let handles: Vec<_> =
|
||||
```
|
||||
|
||||
We introduce a new binding, called `handles`. We’ve given it this name because
|
||||
@ -460,15 +460,15 @@ If you run this program, you’ll see that the philosophers eat out of order!
|
||||
We have multi-threading!
|
||||
|
||||
```text
|
||||
Gilles Deleuze is eating.
|
||||
Gilles Deleuze is done eating.
|
||||
Emma Goldman is eating.
|
||||
Emma Goldman is done eating.
|
||||
Michel Foucault is eating.
|
||||
Judith Butler is eating.
|
||||
Judith Butler is done eating.
|
||||
Gilles Deleuze is eating.
|
||||
Karl Marx is eating.
|
||||
Emma Goldman is eating.
|
||||
Michel Foucault is eating.
|
||||
Judith Butler is done eating.
|
||||
Gilles Deleuze is done eating.
|
||||
Karl Marx is done eating.
|
||||
Emma Goldman is done eating.
|
||||
Michel Foucault is done eating.
|
||||
```
|
||||
|
||||
|
@ -33,8 +33,10 @@ pub fn new(value: T) -> Rc<T> {
|
||||
```
|
||||
|
||||
This code generates documentation that looks [like this][rc-new]. I've left the
|
||||
implementation out, with a regular comment in its place. That's the first thing
|
||||
to notice about this annotation: it uses `///`, instead of `//`. The triple slash
|
||||
implementation out, with a regular comment in its place.
|
||||
|
||||
The first thing to notice about this annotation is that it uses
|
||||
`///` instead of `//`. The triple slash
|
||||
indicates a documentation comment.
|
||||
|
||||
Documentation comments are written in Markdown.
|
||||
@ -375,7 +377,7 @@ $ rustdoc --test path/to/my/crate/root.rs
|
||||
$ cargo test
|
||||
```
|
||||
|
||||
That's right, `cargo test` tests embedded documentation too. However,
|
||||
That's right, `cargo test` tests embedded documentation too. However,
|
||||
`cargo test` will not test binary crates, only library ones. This is
|
||||
due to the way `rustdoc` works: it links against the library to be tested,
|
||||
but with a binary, there’s nothing to link to.
|
||||
|
@ -50,6 +50,8 @@ is very wrong. Wrong enough that we can't continue with things in the current
|
||||
state. Another example is using the `unreachable!()` macro:
|
||||
|
||||
```rust,ignore
|
||||
use Event::NewRelease;
|
||||
|
||||
enum Event {
|
||||
NewRelease,
|
||||
}
|
||||
@ -71,7 +73,7 @@ fn descriptive_probability(event: Event) -> &'static str {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
std::io::println(descriptive_probability(NewRelease));
|
||||
println!("{}", descriptive_probability(NewRelease));
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -309,8 +309,8 @@ and invokes callbacks from there.
|
||||
In these cases access to Rust data structures inside the callbacks is
|
||||
especially unsafe and proper synchronization mechanisms must be used.
|
||||
Besides classical synchronization mechanisms like mutexes, one possibility in
|
||||
Rust is to use channels (in `std::comm`) to forward data from the C thread
|
||||
that invoked the callback into a Rust thread.
|
||||
Rust is to use channels (in `std::sync::mpsc`) to forward data from the C
|
||||
thread that invoked the callback into a Rust thread.
|
||||
|
||||
If an asynchronous callback targets a special object in the Rust address space
|
||||
it is also absolutely necessary that no more callbacks are performed by the
|
||||
@ -340,7 +340,7 @@ libraries:
|
||||
Note that frameworks are only available on OSX targets.
|
||||
|
||||
The different `kind` values are meant to differentiate how the native library
|
||||
participates in linkage. From a linkage perspective, the rust compiler creates
|
||||
participates in linkage. From a linkage perspective, the Rust compiler creates
|
||||
two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
|
||||
Native dynamic library and framework dependencies are propagated to the final
|
||||
artifact boundary, while static library dependencies are not propagated at
|
||||
@ -350,9 +350,9 @@ artifact.
|
||||
A few examples of how this model can be used are:
|
||||
|
||||
* A native build dependency. Sometimes some C/C++ glue is needed when writing
|
||||
some rust code, but distribution of the C/C++ code in a library format is just
|
||||
some Rust code, but distribution of the C/C++ code in a library format is just
|
||||
a burden. In this case, the code will be archived into `libfoo.a` and then the
|
||||
rust crate would declare a dependency via `#[link(name = "foo", kind =
|
||||
Rust crate would declare a dependency via `#[link(name = "foo", kind =
|
||||
"static")]`.
|
||||
|
||||
Regardless of the flavor of output for the crate, the native static library
|
||||
@ -361,7 +361,7 @@ A few examples of how this model can be used are:
|
||||
|
||||
* A normal dynamic dependency. Common system libraries (like `readline`) are
|
||||
available on a large number of systems, and often a static copy of these
|
||||
libraries cannot be found. When this dependency is included in a rust crate,
|
||||
libraries cannot be found. When this dependency is included in a Rust crate,
|
||||
partial targets (like rlibs) will not link to the library, but when the rlib
|
||||
is included in a final target (like a binary), the native library will be
|
||||
linked in.
|
||||
@ -533,19 +533,10 @@ attribute turns off Rust's name mangling, so that it is easier to link to.
|
||||
|
||||
# FFI and panics
|
||||
|
||||
It’s important to be mindful of `panic!`s when working with FFI. This code,
|
||||
when called from C, will `abort`:
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
pub extern fn oh_no() -> ! {
|
||||
panic!("Oops!");
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
If you’re writing code that may panic, you should run it in another thread,
|
||||
so that the panic doesn’t bubble up to C:
|
||||
It’s important to be mindful of `panic!`s when working with FFI. A `panic!`
|
||||
across an FFI boundary is undefined behavior. If you’re writing code that may
|
||||
panic, you should run it in another thread, so that the panic doesn’t bubble up
|
||||
to C:
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
|
@ -360,10 +360,12 @@ rand="0.3.0"
|
||||
The `[dependencies]` section of `Cargo.toml` is like the `[package]` section:
|
||||
everything that follows it is part of it, until the next section starts.
|
||||
Cargo uses the dependencies section to know what dependencies on external
|
||||
crates you have, and what versions you require. In this case, we’ve used version `0.3.0`.
|
||||
crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`,
|
||||
which Cargo understands to be any release that’s compatible with this specific version.
|
||||
Cargo understands [Semantic Versioning][semver], which is a standard for writing version
|
||||
numbers. If we wanted to use the latest version we could use `*` or we could use a range
|
||||
of versions. [Cargo’s documentation][cargodoc] contains more details.
|
||||
numbers. If we wanted to use only `0.3.0` exactly, we could use `=0.3.0`. If we
|
||||
wanted to use the latest version we could use `*`; We could use a range of
|
||||
versions. [Cargo’s documentation][cargodoc] contains more details.
|
||||
|
||||
[semver]: http://semver.org
|
||||
[cargodoc]: http://doc.crates.io/crates-io.html
|
||||
|
@ -103,7 +103,7 @@ fn main() {
|
||||
If you would like to use real operands in this position, however,
|
||||
you are required to put curly braces `{}` around the register that
|
||||
you want, and you are required to put the specific size of the
|
||||
operand. This is useful for very low level programming, where
|
||||
operand. This is useful for very low level programming, where
|
||||
which register you use is important:
|
||||
|
||||
```rust
|
||||
@ -166,3 +166,12 @@ unsafe {
|
||||
println!("eax is currently {}", result);
|
||||
# }
|
||||
```
|
||||
|
||||
## More Information
|
||||
|
||||
The current implementation of the `asm!` macro is a direct binding to [LLVM's
|
||||
inline assembler expressions][llvm-docs], so be sure to check out [their
|
||||
documentation as well][llvm-docs] for more information about clobbers,
|
||||
constraints, etc.
|
||||
|
||||
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
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:
|
||||
or a Mac, all you need to do is this:
|
||||
|
||||
> Note: you don't need to type in the `$`s, they just indicate the start of
|
||||
> each command. You’ll see many tutorials and examples around the web that
|
||||
@ -25,6 +25,12 @@ $ sh rustup.sh
|
||||
[insecurity]: http://curlpipesh.tumblr.com
|
||||
|
||||
If you're on Windows, please download the appropriate [installer][install-page].
|
||||
**NOTE:** By default, the Windows installer will not add Rust to the %PATH%
|
||||
system variable. If this is the only version of Rust you are installing and you
|
||||
want to be able to run it from the command line, click on "Advanced" on the
|
||||
install dialog and on the "Product Features" page ensure "Add to PATH" is
|
||||
installed on the local hard drive.
|
||||
|
||||
|
||||
[install-page]: http://www.rust-lang.org/install.html
|
||||
|
||||
@ -87,6 +93,11 @@ rustc 1.0.0 (a59de37e9 2015-05-13)
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
|
||||
If you didn't and you're on Windows, check that Rust is in your %PATH% system
|
||||
variable. If it isn't, run the installer again, select "Change" on the "Change,
|
||||
repair, or remove installation" page and ensure "Add to PATH" is installed on
|
||||
the local hard drive.
|
||||
|
||||
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
|
||||
@ -101,5 +112,5 @@ resources include [the user’s forum][users], and
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[users]: http://users.rust-lang.org/
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
@ -101,6 +101,8 @@ the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
|
||||
i32` as ‘a mutable reference to an i32’ and `&'a mut i32` as ‘a mutable
|
||||
reference to an `i32` with the lifetime `'a`’.
|
||||
|
||||
# In `struct`s
|
||||
|
||||
You’ll also need explicit lifetimes when working with [`struct`][structs]s:
|
||||
|
||||
```rust
|
||||
@ -137,6 +139,33 @@ x: &'a i32,
|
||||
uses it. So why do we need a lifetime here? We need to ensure that any reference
|
||||
to a `Foo` cannot outlive the reference to an `i32` it contains.
|
||||
|
||||
## `impl` blocks
|
||||
|
||||
Let’s implement a method on `Foo`:
|
||||
|
||||
```rust
|
||||
struct Foo<'a> {
|
||||
x: &'a i32,
|
||||
}
|
||||
|
||||
impl<'a> Foo<'a> {
|
||||
fn x(&self) -> &'a i32 { self.x }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
|
||||
let f = Foo { x: y };
|
||||
|
||||
println!("x is: {}", f.x());
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat
|
||||
`'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>`
|
||||
uses it.
|
||||
|
||||
## Multiple lifetimes
|
||||
|
||||
If you have multiple references, you can use the same lifetime multiple times:
|
||||
|
||||
```rust
|
||||
|
@ -1,25 +0,0 @@
|
||||
% Link args
|
||||
|
||||
There is one other way to tell rustc how to customize linking, and that is via
|
||||
the `link_args` attribute. This attribute is applied to `extern` blocks and
|
||||
specifies raw flags which need to get passed to the linker when producing an
|
||||
artifact. An example usage would be:
|
||||
|
||||
``` no_run
|
||||
#![feature(link_args)]
|
||||
|
||||
#[link_args = "-foo -bar -baz"]
|
||||
extern {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
||||
because this is not a sanctioned way of performing linking. Right now rustc
|
||||
shells out to the system linker, so it makes sense to provide extra command line
|
||||
arguments, but this will not always be the case. In the future rustc may use
|
||||
LLVM directly to link native libraries in which case `link_args` will have no
|
||||
meaning.
|
||||
|
||||
It is highly recommended to *not* use this attribute, and rather use the more
|
||||
formal `#[link(...)]` attribute on `extern` blocks instead.
|
||||
|
@ -42,8 +42,8 @@ With that in mind, let’s learn about ownership.
|
||||
# Ownership
|
||||
|
||||
[Variable bindings][bindings] have a property in Rust: they ‘have ownership’
|
||||
of what they’re bound to. This means that when a binding goes out of scope, the
|
||||
resource that they’re bound to are freed. For example:
|
||||
of what they’re bound to. This means that when a binding goes out of scope,
|
||||
Rust will free the bound resources. For example:
|
||||
|
||||
```rust
|
||||
fn foo() {
|
||||
|
@ -282,6 +282,38 @@ This ‘destructuring’ behavior works on any compound data type, like
|
||||
[tuples]: primitive-types.html#tuples
|
||||
[enums]: enums.html
|
||||
|
||||
# Ignoring bindings
|
||||
|
||||
You can use `_` in a pattern to disregard the value. For example, here’s a
|
||||
`match` against a `Result<T, E>`:
|
||||
|
||||
```rust
|
||||
# let some_value: Result<i32, &'static str> = Err("There was an error");
|
||||
match some_value {
|
||||
Ok(value) => println!("got a value: {}", value),
|
||||
Err(_) => println!("an error occurred"),
|
||||
}
|
||||
```
|
||||
|
||||
In the first arm, we bind the value inside the `Ok` variant to `value`. But
|
||||
in the `Err` arm, we use `_` to disregard the specific error, and just print
|
||||
a general error message.
|
||||
|
||||
`_` is valid in any pattern that creates a binding. This can be useful to
|
||||
ignore parts of a larger structure:
|
||||
|
||||
```rust
|
||||
fn coordinate() -> (i32, i32, i32) {
|
||||
// generate and return some sort of triple tuple
|
||||
# (1, 2, 3)
|
||||
}
|
||||
|
||||
let (x, _, z) = coordinate();
|
||||
```
|
||||
|
||||
Here, we bind the first and last element of the tuple to `x` and `z`, but
|
||||
ignore the middle element.
|
||||
|
||||
# Mix and Match
|
||||
|
||||
Whew! That’s a lot of different ways to match things, and they can all be
|
||||
|
@ -336,7 +336,9 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as
|
||||
the borrow ‘doesn’t live long enough’ because it’s not valid for the right
|
||||
amount of time.
|
||||
|
||||
The same problem occurs when the reference is declared _before_ the variable it refers to:
|
||||
The same problem occurs when the reference is declared _before_ the variable it
|
||||
refers to. This is because resources within the same scope are freed in the
|
||||
opposite order they were declared:
|
||||
|
||||
```rust,ignore
|
||||
let y: &i32;
|
||||
@ -369,3 +371,6 @@ statement 1 at 3:14
|
||||
println!("{}", y);
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, `y` is declared before `x`, meaning that `y` lives longer
|
||||
than `x`, which is not allowed.
|
||||
|
@ -43,3 +43,26 @@ This will help alert the team in case there’s an accidental regression.
|
||||
Additionally, testing against nightly can catch regressions even sooner, and so
|
||||
if you don’t mind a third build, we’d appreciate testing against all channels.
|
||||
|
||||
As an example, many Rust programmers use [Travis](https://travis-ci.org/) to
|
||||
test their crates, which is free for open source projects. Travis [supports
|
||||
Rust directly][travis], and you can use a `.travis.yml` file like this to
|
||||
test on all channels:
|
||||
|
||||
```yaml
|
||||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
```
|
||||
|
||||
[travis]: http://docs.travis-ci.com/user/languages/rust/
|
||||
|
||||
With this configuration, Travis will test all three channels, but if something
|
||||
breaks on nightly, it won’t fail your build. A similar configuration is
|
||||
recommended for any CI system, check the documentation of the one you’re
|
||||
using for more details.
|
||||
|
@ -250,11 +250,10 @@ that our tests are entirely left out of a normal build.
|
||||
|
||||
The second change is the `use` declaration. Because we're in an inner module,
|
||||
we need to bring our test function into scope. This can be annoying if you have
|
||||
a large module, and so this is a common use of the `glob` feature. Let's change
|
||||
our `src/lib.rs` to make use of it:
|
||||
a large module, and so this is a common use of globs. Let's change our
|
||||
`src/lib.rs` to make use of it:
|
||||
|
||||
```rust,ignore
|
||||
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and
|
||||
| 1 | a | 5 |
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then `foo()` ends, leaving just `main()`
|
||||
And then `foo()` ends, leaving just `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|---------|------|-------|
|
||||
@ -537,7 +537,7 @@ Generally, you should prefer stack allocation, and so, Rust stack-allocates by
|
||||
default. The LIFO model of the stack is simpler, at a fundamental level. This
|
||||
has two big impacts: runtime efficiency and semantic impact.
|
||||
|
||||
## Runtime Efficiency.
|
||||
## Runtime Efficiency
|
||||
|
||||
Managing the memory for the stack is trivial: The machine just
|
||||
increments or decrements a single value, the so-called “stack pointer”.
|
||||
|
@ -8,11 +8,11 @@ this, Rust has a keyword, `unsafe`. Code using `unsafe` has less restrictions
|
||||
than normal code does.
|
||||
|
||||
Let’s go over the syntax, and then we’ll talk semantics. `unsafe` is used in
|
||||
two contexts. The first one is to mark a function as unsafe:
|
||||
four contexts. The first one is to mark a function as unsafe:
|
||||
|
||||
```rust
|
||||
unsafe fn danger_will_robinson() {
|
||||
// scary stuff
|
||||
// scary stuff
|
||||
}
|
||||
```
|
||||
|
||||
@ -27,15 +27,40 @@ unsafe {
|
||||
}
|
||||
```
|
||||
|
||||
The third is for unsafe traits:
|
||||
|
||||
```rust
|
||||
unsafe trait Scary { }
|
||||
```
|
||||
|
||||
And the fourth is for `impl`ementing one of those traits:
|
||||
|
||||
```rust
|
||||
# unsafe trait Scary { }
|
||||
unsafe impl Scary for i32 {}
|
||||
```
|
||||
|
||||
It’s important to be able to explicitly delineate code that may have bugs that
|
||||
cause big problems. If a Rust program segfaults, you can be sure it’s somewhere
|
||||
in the sections marked `unsafe`.
|
||||
|
||||
# What does ‘safe’ mean?
|
||||
|
||||
Safe, in the context of Rust, means “doesn’t do anything unsafe.” Easy!
|
||||
Safe, in the context of Rust, means ‘doesn’t do anything unsafe’. It’s also
|
||||
important to know that there are certain behaviors that are probably not
|
||||
desirable in your code, but are expressly _not_ unsafe:
|
||||
|
||||
Okay, let’s try again: what is not safe to do? Here’s a list:
|
||||
* Deadlocks
|
||||
* Leaks of memory or other resources
|
||||
* Exiting without calling destructors
|
||||
* Integer overflow
|
||||
|
||||
Rust cannot prevent all kinds of software problems. Buggy code can and will be
|
||||
written in Rust. These things aren’t great, but they don’t qualify as `unsafe`
|
||||
specifically.
|
||||
|
||||
In addition, the following are all undefined behaviors in Rust, and must be
|
||||
avoided, even when writing `unsafe` code:
|
||||
|
||||
* Data races
|
||||
* Dereferencing a null/dangling raw pointer
|
||||
@ -64,21 +89,6 @@ Okay, let’s try again: what is not safe to do? Here’s a list:
|
||||
[undef]: http://llvm.org/docs/LangRef.html#undefined-values
|
||||
[aliasing]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules
|
||||
|
||||
Whew! That’s a bunch of stuff. It’s also important to notice all kinds of
|
||||
behaviors that are certainly bad, but are expressly _not_ unsafe:
|
||||
|
||||
* Deadlocks
|
||||
* Reading data from private fields
|
||||
* Leaks due to reference count cycles
|
||||
* Exiting without calling destructors
|
||||
* Sending signals
|
||||
* Accessing/modifying the file system
|
||||
* Integer overflow
|
||||
|
||||
Rust cannot prevent all kinds of software problems. Buggy code can and will be
|
||||
written in Rust. These things aren’t great, but they don’t qualify as `unsafe`
|
||||
specifically.
|
||||
|
||||
# Unsafe Superpowers
|
||||
|
||||
In both unsafe functions and unsafe blocks, Rust will let you do three things
|
||||
@ -90,10 +100,14 @@ that you normally can not do. Just three. Here they are:
|
||||
|
||||
That’s it. It’s important that `unsafe` does not, for example, ‘turn off the
|
||||
borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its
|
||||
semantics, it won’t just start accepting anything.
|
||||
semantics, it won’t just start accepting anything. But it will let you write
|
||||
things that _do_ break some of the rules.
|
||||
|
||||
But it will let you write things that _do_ break some of the rules. Let’s go
|
||||
over these three abilities in order.
|
||||
You will also encounter the `unsafe` keyword when writing bindings to foreign
|
||||
(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface
|
||||
around the methods provided by the library.
|
||||
|
||||
Let’s go over the basic three abilities listed, in order.
|
||||
|
||||
## Access or update a `static mut`
|
||||
|
||||
|
@ -88,6 +88,24 @@ for x in 0..10 {
|
||||
}
|
||||
```
|
||||
|
||||
You may also encounter situations where you have nested loops and need to
|
||||
specify which one your `break` or `continue` statement is for. Like most
|
||||
other languages, by default a `break` or `continue` will apply to innermost
|
||||
loop. In a sitation where you would like to a `break` or `continue` for one
|
||||
of the outer loops, you can use labels to specify which loop the `break` or
|
||||
`continue` statement applies to. This will only print when both `x` and `y` are
|
||||
odd:
|
||||
|
||||
```rust
|
||||
'outer: for x in 0..10 {
|
||||
'inner: for y in 0..10 {
|
||||
if x % 2 == 0 { continue 'outer; } // continues the loop over x
|
||||
if y % 2 == 0 { continue 'inner; } // continues the loop over y
|
||||
println!("x: {}, y: {}", x, y);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Both `continue` and `break` are valid in both `while` loops and [`for` loops][for].
|
||||
|
||||
[for]: for-loops.html
|
||||
|
@ -55,12 +55,10 @@ SLICE_FIELD_NAME_LENGTH = "length"
|
||||
SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
|
||||
|
||||
# std::Vec<> related constants
|
||||
STD_VEC_FIELD_NAME_DATA_PTR = "ptr"
|
||||
STD_VEC_FIELD_NAME_LENGTH = "len"
|
||||
STD_VEC_FIELD_NAME_CAPACITY = "cap"
|
||||
STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_DATA_PTR,
|
||||
STD_VEC_FIELD_NAME_LENGTH,
|
||||
STD_VEC_FIELD_NAME_CAPACITY]
|
||||
STD_VEC_FIELD_NAME_BUF = "buf"
|
||||
STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF,
|
||||
STD_VEC_FIELD_NAME_LENGTH]
|
||||
|
||||
# std::String related constants
|
||||
STD_STRING_FIELD_NAMES = ["vec"]
|
||||
@ -302,13 +300,13 @@ def get_discriminant_value_as_integer(enum_val):
|
||||
def extract_length_ptr_and_cap_from_std_vec(vec_val):
|
||||
assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
|
||||
length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
|
||||
ptr_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_DATA_PTR)
|
||||
cap_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_CAPACITY)
|
||||
buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF)
|
||||
|
||||
length = vec_val.get_child_at_index(length_field_index).as_integer()
|
||||
vec_ptr_val = vec_val.get_child_at_index(ptr_field_index)
|
||||
capacity = vec_val.get_child_at_index(cap_field_index).as_integer()
|
||||
buf = vec_val.get_child_at_index(buf_field_index)
|
||||
|
||||
vec_ptr_val = buf.get_child_at_index(0)
|
||||
capacity = buf.get_child_at_index(1).as_integer()
|
||||
unique_ptr_val = vec_ptr_val.get_child_at_index(0)
|
||||
data_ptr = unique_ptr_val.get_child_at_index(0)
|
||||
assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
|
||||
|
@ -23,6 +23,18 @@ src_dir = sys.argv[1]
|
||||
errcode_map = {}
|
||||
error_re = re.compile("(E\d\d\d\d)")
|
||||
|
||||
# In the register_long_diagnostics! macro, entries look like this:
|
||||
#
|
||||
# EXXXX: r##"
|
||||
# <Long diagnostic message>
|
||||
# "##,
|
||||
#
|
||||
# These two variables are for detecting the beginning and end of diagnostic
|
||||
# messages so that duplicate error codes are not reported when a code occurs
|
||||
# inside a diagnostic message
|
||||
long_diag_begin = "r##\""
|
||||
long_diag_end = "\"##"
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk(src_dir):
|
||||
if "src/test" in dirpath or "src/llvm" in dirpath:
|
||||
# Short circuit for fast
|
||||
@ -35,7 +47,14 @@ for (dirpath, dirnames, filenames) in os.walk(src_dir):
|
||||
path = os.path.join(dirpath, filename)
|
||||
|
||||
with open(path, 'r') as f:
|
||||
inside_long_diag = False
|
||||
for line_num, line in enumerate(f, start=1):
|
||||
if inside_long_diag:
|
||||
# Skip duplicate error code checking for this line
|
||||
if long_diag_end in line:
|
||||
inside_long_diag = False
|
||||
continue
|
||||
|
||||
match = error_re.search(line)
|
||||
if match:
|
||||
errcode = match.group(1)
|
||||
@ -47,6 +66,9 @@ for (dirpath, dirnames, filenames) in os.walk(src_dir):
|
||||
else:
|
||||
errcode_map[errcode] = new_record
|
||||
|
||||
if long_diag_begin in line:
|
||||
inside_long_diag = True
|
||||
|
||||
errors = False
|
||||
all_errors = []
|
||||
|
||||
|
@ -14,10 +14,9 @@ import subprocess
|
||||
|
||||
f = open(sys.argv[1], 'wb')
|
||||
|
||||
components = sys.argv[2].split(' ')
|
||||
components = [i for i in components if i] # ignore extra whitespaces
|
||||
components = sys.argv[2].split() # splits on whitespace
|
||||
enable_static = sys.argv[3]
|
||||
llconfig = sys.argv[4]
|
||||
llvm_config = sys.argv[4]
|
||||
|
||||
f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
@ -39,7 +38,7 @@ def run(args):
|
||||
out, err = proc.communicate()
|
||||
|
||||
if err:
|
||||
print("failed to run llconfig: args = `{}`".format(args))
|
||||
print("failed to run llvm_config: args = `{}`".format(args))
|
||||
print(err)
|
||||
sys.exit(1)
|
||||
return out
|
||||
@ -47,7 +46,7 @@ def run(args):
|
||||
f.write("\n")
|
||||
|
||||
# LLVM libs
|
||||
args = [llconfig, '--libs', '--system-libs']
|
||||
args = [llvm_config, '--libs', '--system-libs']
|
||||
|
||||
args.extend(components)
|
||||
out = run(args)
|
||||
@ -69,13 +68,13 @@ for lib in out.strip().replace("\n", ' ').split(' '):
|
||||
f.write(")]\n")
|
||||
|
||||
# LLVM ldflags
|
||||
out = run([llconfig, '--ldflags'])
|
||||
out = run([llvm_config, '--ldflags'])
|
||||
for lib in out.strip().split(' '):
|
||||
if lib[:2] == "-l":
|
||||
f.write("#[link(name = \"" + lib[2:] + "\")]\n")
|
||||
|
||||
# C++ runtime library
|
||||
out = run([llconfig, '--cxxflags'])
|
||||
out = run([llvm_config, '--cxxflags'])
|
||||
if enable_static == '1':
|
||||
assert('stdlib=libc++' not in out)
|
||||
f.write("#[link(name = \"stdc++\", kind = \"static\")]\n")
|
||||
|
@ -41,13 +41,14 @@ download_dir_base = "dl"
|
||||
download_unpack_base = os.path.join(download_dir_base, "unpack")
|
||||
|
||||
snapshot_files = {
|
||||
"bitrig": ["bin/rustc"],
|
||||
"dragonfly": ["bin/rustc"],
|
||||
"freebsd": ["bin/rustc"],
|
||||
"linux": ["bin/rustc"],
|
||||
"macos": ["bin/rustc"],
|
||||
"winnt": ["bin/rustc.exe"],
|
||||
"freebsd": ["bin/rustc"],
|
||||
"dragonfly": ["bin/rustc"],
|
||||
"bitrig": ["bin/rustc"],
|
||||
"netbsd": ["bin/rustc"],
|
||||
"openbsd": ["bin/rustc"],
|
||||
"winnt": ["bin/rustc.exe"],
|
||||
}
|
||||
|
||||
winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"]
|
||||
@ -103,6 +104,8 @@ def get_kernel(triple):
|
||||
return "dragonfly"
|
||||
if os_name == "bitrig":
|
||||
return "bitrig"
|
||||
if os_name == "netbsd":
|
||||
return "netbsd"
|
||||
if os_name == "openbsd":
|
||||
return "openbsd"
|
||||
return "linux"
|
||||
|
@ -372,13 +372,6 @@ def emit_conversions_module(f, to_upper, to_lower, to_title):
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_title(c: char) -> [char; 3] {
|
||||
match bsearch_case_table(c, to_titlecase_table) {
|
||||
None => [c, '\\0', '\\0'],
|
||||
Some(index) => to_titlecase_table[index].1
|
||||
}
|
||||
}
|
||||
|
||||
fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option<usize> {
|
||||
match table.binary_search_by(|&(key, _)| {
|
||||
if c == key { Equal }
|
||||
@ -400,9 +393,6 @@ def emit_conversions_module(f, to_upper, to_lower, to_title):
|
||||
emit_table(f, "to_uppercase_table",
|
||||
sorted(to_upper.iteritems(), key=operator.itemgetter(0)),
|
||||
is_pub=False, t_type = t_type, pfun=pfun)
|
||||
emit_table(f, "to_titlecase_table",
|
||||
sorted(to_title.iteritems(), key=operator.itemgetter(0)),
|
||||
is_pub=False, t_type = t_type, pfun=pfun)
|
||||
f.write("}\n\n")
|
||||
|
||||
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
|
||||
|
@ -77,13 +77,15 @@ use core::atomic;
|
||||
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
|
||||
use core::fmt;
|
||||
use core::cmp::Ordering;
|
||||
use core::mem::{min_align_of_val, size_of_val};
|
||||
use core::mem::{align_of_val, size_of_val};
|
||||
use core::intrinsics::drop_in_place;
|
||||
use core::mem;
|
||||
use core::nonzero::NonZero;
|
||||
use core::ops::{Deref, CoerceUnsized};
|
||||
use core::ptr;
|
||||
use core::marker::Unsize;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::usize;
|
||||
use heap::deallocate;
|
||||
|
||||
/// An atomically reference counted wrapper for shared state.
|
||||
@ -145,6 +147,8 @@ pub struct Weak<T: ?Sized> {
|
||||
unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> { }
|
||||
unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> { }
|
||||
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@ -154,7 +158,12 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
|
||||
|
||||
struct ArcInner<T: ?Sized> {
|
||||
strong: atomic::AtomicUsize,
|
||||
|
||||
// the value usize::MAX acts as a sentinel for temporarily "locking" the
|
||||
// ability to upgrade weak pointers or downgrade strong ones; this is used
|
||||
// to avoid races in `make_unique` and `get_mut`.
|
||||
weak: atomic::AtomicUsize,
|
||||
|
||||
data: T,
|
||||
}
|
||||
|
||||
@ -201,9 +210,25 @@ impl<T: ?Sized> Arc<T> {
|
||||
#[unstable(feature = "arc_weak",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
// See the clone() impl for why this is relaxed
|
||||
self.inner().weak.fetch_add(1, Relaxed);
|
||||
Weak { _ptr: self._ptr }
|
||||
loop {
|
||||
// This Relaxed is OK because we're checking the value in the CAS
|
||||
// below.
|
||||
let cur = self.inner().weak.load(Relaxed);
|
||||
|
||||
// check if the weak counter is currently "locked"; if so, spin.
|
||||
if cur == usize::MAX { continue }
|
||||
|
||||
// NOTE: this code currently ignores the possibility of overflow
|
||||
// into usize::MAX; in general both Rc and Arc need to be adjusted
|
||||
// to deal with overflow.
|
||||
|
||||
// Unlike with Clone(), we need this to be an Acquire read to
|
||||
// synchronize with the write coming from `is_unique`, so that the
|
||||
// events prior to that write happen before this read.
|
||||
if self.inner().weak.compare_and_swap(cur, cur + 1, Acquire) == cur {
|
||||
return Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
@ -241,7 +266,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
|
||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||
atomic::fence(Acquire);
|
||||
deallocate(ptr as *mut u8, size_of_val(&*ptr), min_align_of_val(&*ptr))
|
||||
deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,51 +283,6 @@ pub fn weak_count<T: ?Sized>(this: &Arc<T>) -> usize { Arc::weak_count(this) }
|
||||
#[deprecated(since = "1.2.0", reason = "renamed to Arc::strong_count")]
|
||||
pub fn strong_count<T: ?Sized>(this: &Arc<T>) -> usize { Arc::strong_count(this) }
|
||||
|
||||
|
||||
/// Returns a mutable reference to the contained value if the `Arc<T>` is unique.
|
||||
///
|
||||
/// Returns `None` if the `Arc<T>` is not unique.
|
||||
///
|
||||
/// This function is marked **unsafe** because it is racy if weak pointers
|
||||
/// are active.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(arc_unique, alloc)]
|
||||
/// extern crate alloc;
|
||||
/// # fn main() {
|
||||
/// use alloc::arc::{Arc, get_mut};
|
||||
///
|
||||
/// # unsafe {
|
||||
/// 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());
|
||||
/// # }
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_unique")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "this function is unsafe with weak pointers")]
|
||||
pub unsafe fn get_mut<T: ?Sized>(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
// FIXME(#24880) potential race with upgraded weak pointers here
|
||||
if Arc::strong_count(this) == 1 && Arc::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
|
||||
// reference count is guaranteed to be 1 at this point, and we required
|
||||
// the Arc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
let inner = &mut **this._ptr;
|
||||
Some(&mut inner.data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for Arc<T> {
|
||||
/// Makes a clone of the `Arc<T>`.
|
||||
@ -350,10 +330,9 @@ impl<T: Clone> Arc<T> {
|
||||
/// Make a mutable reference from the given `Arc<T>`.
|
||||
///
|
||||
/// This is also referred to as a copy-on-write operation because the inner
|
||||
/// data is cloned if the reference count is greater than one.
|
||||
///
|
||||
/// This method is marked **unsafe** because it is racy if weak pointers
|
||||
/// are active.
|
||||
/// data is cloned if the (strong) reference count is greater than one. If
|
||||
/// we hold the only strong reference, any existing weak references will no
|
||||
/// longer be upgradeable.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -361,31 +340,138 @@ impl<T: Clone> Arc<T> {
|
||||
/// # #![feature(arc_unique)]
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// # unsafe {
|
||||
/// let mut five = Arc::new(5);
|
||||
///
|
||||
/// let mut_five = five.make_unique();
|
||||
/// let mut_five = Arc::make_unique(&mut five);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_unique")]
|
||||
pub fn make_unique(this: &mut Arc<T>) -> &mut T {
|
||||
// Note that we hold both a strong reference and a weak reference.
|
||||
// Thus, releasing our strong reference only will not, by itself, cause
|
||||
// the memory to be deallocated.
|
||||
//
|
||||
// Use Acquire to ensure that we see any writes to `weak` that happen
|
||||
// before release writes (i.e., decrements) to `strong`. Since we hold a
|
||||
// weak count, there's no chance the ArcInner itself could be
|
||||
// deallocated.
|
||||
if this.inner().strong.compare_and_swap(1, 0, Acquire) != 1 {
|
||||
// Another srong pointer exists; clone
|
||||
*this = Arc::new((**this).clone());
|
||||
} else if this.inner().weak.load(Relaxed) != 1 {
|
||||
// Relaxed suffices in the above because this is fundamentally an
|
||||
// optimization: we are always racing with weak pointers being
|
||||
// dropped. Worst case, we end up allocated a new Arc unnecessarily.
|
||||
|
||||
// We removed the last strong ref, but there are additional weak
|
||||
// refs remaining. We'll move the contents to a new Arc, and
|
||||
// invalidate the other weak refs.
|
||||
|
||||
// Note that it is not possible for the read of `weak` to yield
|
||||
// usize::MAX (i.e., locked), since the weak count can only be
|
||||
// locked by a thread with a strong reference.
|
||||
|
||||
// Materialize our own implicit weak pointer, so that it can clean
|
||||
// up the ArcInner as needed.
|
||||
let weak = Weak { _ptr: this._ptr };
|
||||
|
||||
// mark the data itself as already deallocated
|
||||
unsafe {
|
||||
// there is no data race in the implicit write caused by `read`
|
||||
// here (due to zeroing) because data is no longer accessed by
|
||||
// other threads (due to there being no more strong refs at this
|
||||
// point).
|
||||
let mut swap = Arc::new(ptr::read(&(**weak._ptr).data));
|
||||
mem::swap(this, &mut swap);
|
||||
mem::forget(swap);
|
||||
}
|
||||
} else {
|
||||
// We were the sole reference of either kind; bump back up the
|
||||
// strong ref count.
|
||||
this.inner().strong.store(1, Release);
|
||||
}
|
||||
|
||||
// As with `get_mut()`, the unsafety is ok because our reference was
|
||||
// either unique to begin with, or became one upon cloning the contents.
|
||||
unsafe {
|
||||
let inner = &mut **this._ptr;
|
||||
&mut inner.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Returns a mutable reference to the contained value if the `Arc<T>` is unique.
|
||||
///
|
||||
/// Returns `None` if the `Arc<T>` is not unique.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(arc_unique, alloc)]
|
||||
/// extern crate alloc;
|
||||
/// # fn main() {
|
||||
/// use alloc::arc::Arc;
|
||||
///
|
||||
/// let mut x = Arc::new(3);
|
||||
/// *Arc::get_mut(&mut x).unwrap() = 4;
|
||||
/// assert_eq!(*x, 4);
|
||||
///
|
||||
/// let _y = x.clone();
|
||||
/// assert!(Arc::get_mut(&mut x).is_none());
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_unique")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "this function is unsafe with weak pointers")]
|
||||
pub unsafe fn make_unique(&mut self) -> &mut T {
|
||||
// FIXME(#24880) potential race with upgraded weak pointers here
|
||||
//
|
||||
// Note that we hold a strong reference, which also counts as a weak
|
||||
// reference, so we only clone if there is an additional reference of
|
||||
// either kind.
|
||||
if self.inner().strong.load(SeqCst) != 1 ||
|
||||
self.inner().weak.load(SeqCst) != 1 {
|
||||
*self = Arc::new((**self).clone())
|
||||
pub fn get_mut(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
if this.is_unique() {
|
||||
// This unsafety is ok because we're guaranteed that the pointer
|
||||
// returned is the *only* pointer that will ever be returned to T. Our
|
||||
// reference count is guaranteed to be 1 at this point, and we required
|
||||
// the Arc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
unsafe {
|
||||
let inner = &mut **this._ptr;
|
||||
Some(&mut inner.data)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// 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 = &mut **self._ptr;
|
||||
&mut inner.data
|
||||
}
|
||||
|
||||
/// Determine whether this is the unique reference (including weak refs) to
|
||||
/// the underlying data.
|
||||
///
|
||||
/// Note that this requires locking the weak ref count.
|
||||
fn is_unique(&mut self) -> bool {
|
||||
// lock the weak pointer count if we appear to be the sole weak pointer
|
||||
// holder.
|
||||
//
|
||||
// The acquire label here ensures a happens-before relationship with any
|
||||
// writes to `strong` prior to decrements of the `weak` count (via drop,
|
||||
// which uses Release).
|
||||
if self.inner().weak.compare_and_swap(1, usize::MAX, Acquire) == 1 {
|
||||
// Due to the previous acquire read, this will observe any writes to
|
||||
// `strong` that were due to upgrading weak pointers; only strong
|
||||
// clones remain, which require that the strong count is > 1 anyway.
|
||||
let unique = self.inner().strong.load(Relaxed) == 1;
|
||||
|
||||
// The release write here synchronizes with a read in `downgrade`,
|
||||
// effectively preventing the above read of `strong` from happening
|
||||
// after the write.
|
||||
self.inner().weak.store(1, Release); // release the lock
|
||||
unique
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_unique")]
|
||||
#[deprecated(since = "1.2", reason = "use Arc::get_mut instead")]
|
||||
pub fn get_mut<T: ?Sized>(this: &mut Arc<T>) -> Option<&mut T> {
|
||||
Arc::get_mut(this)
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -483,9 +569,15 @@ impl<T: ?Sized> Weak<T> {
|
||||
// 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);
|
||||
// Relaxed load because any write of 0 that we can observe
|
||||
// leaves the field in a permanently zero state (so a
|
||||
// "stale" read of 0 is fine), and any other value is
|
||||
// confirmed via the CAS below.
|
||||
let n = inner.strong.load(Relaxed);
|
||||
if n == 0 { return None }
|
||||
let old = inner.strong.compare_and_swap(n, n + 1, SeqCst);
|
||||
|
||||
// Relaxed is valid for the same reason it is on Arc's Clone impl
|
||||
let old = inner.strong.compare_and_swap(n, n + 1, Relaxed);
|
||||
if old == n { return Some(Arc { _ptr: self._ptr }) }
|
||||
}
|
||||
}
|
||||
@ -516,9 +608,12 @@ impl<T: ?Sized> Clone for Weak<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Weak<T> {
|
||||
// See comments in Arc::clone() for why this is relaxed
|
||||
// See comments in Arc::clone() for why this is relaxed. This can use a
|
||||
// fetch_add (ignoring the lock) because the weak count is only locked
|
||||
// where are *no other* weak pointers in existence. (So we can't be
|
||||
// running this code in that case).
|
||||
self.inner().weak.fetch_add(1, Relaxed);
|
||||
Weak { _ptr: self._ptr }
|
||||
return Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,11 +656,16 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
// If we find out that we were the last weak pointer, then its time to
|
||||
// deallocate the data entirely. See the discussion in Arc::drop() about
|
||||
// the memory orderings
|
||||
//
|
||||
// It's not necessary to check for the locked state here, because the
|
||||
// weak count can only be locked if there was precisely one weak ref,
|
||||
// meaning that drop could only subsequently run ON that remaining weak
|
||||
// ref, which can only happen after the lock is released.
|
||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||
atomic::fence(Acquire);
|
||||
unsafe { deallocate(ptr as *mut u8,
|
||||
size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr)) }
|
||||
align_of_val(&*ptr)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -792,13 +892,13 @@ mod tests {
|
||||
let mut cow1 = cow0.clone();
|
||||
let mut cow2 = cow1.clone();
|
||||
|
||||
assert!(75 == *cow0.make_unique());
|
||||
assert!(75 == *cow1.make_unique());
|
||||
assert!(75 == *cow2.make_unique());
|
||||
assert!(75 == *Arc::make_unique(&mut cow0));
|
||||
assert!(75 == *Arc::make_unique(&mut cow1));
|
||||
assert!(75 == *Arc::make_unique(&mut cow2));
|
||||
|
||||
*cow0.make_unique() += 1;
|
||||
*cow1.make_unique() += 2;
|
||||
*cow2.make_unique() += 3;
|
||||
*Arc::make_unique(&mut cow0) += 1;
|
||||
*Arc::make_unique(&mut cow1) += 2;
|
||||
*Arc::make_unique(&mut cow2) += 3;
|
||||
|
||||
assert!(76 == *cow0);
|
||||
assert!(77 == *cow1);
|
||||
@ -822,7 +922,7 @@ mod tests {
|
||||
assert!(75 == *cow2);
|
||||
|
||||
unsafe {
|
||||
*cow0.make_unique() += 1;
|
||||
*Arc::make_unique(&mut cow0) += 1;
|
||||
}
|
||||
|
||||
assert!(76 == *cow0);
|
||||
@ -845,7 +945,7 @@ mod tests {
|
||||
assert!(75 == *cow1_weak.upgrade().unwrap());
|
||||
|
||||
unsafe {
|
||||
*cow0.make_unique() += 1;
|
||||
*Arc::make_unique(&mut cow0) += 1;
|
||||
}
|
||||
|
||||
assert!(76 == *cow0);
|
||||
|
@ -55,14 +55,17 @@
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use heap;
|
||||
|
||||
use core::any::Any;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::marker::Unsize;
|
||||
use core::marker::{self, Unsize};
|
||||
use core::mem;
|
||||
use core::ops::{CoerceUnsized, Deref, DerefMut};
|
||||
use core::ptr::{Unique};
|
||||
use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
|
||||
use core::ptr::Unique;
|
||||
use core::raw::{TraitObject};
|
||||
|
||||
/// A value that represents the heap. This is the default place that the `box`
|
||||
@ -72,7 +75,7 @@ use core::raw::{TraitObject};
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(box_heap)]
|
||||
/// #![feature(box_syntax)]
|
||||
/// #![feature(box_syntax, placement_in_syntax)]
|
||||
/// use std::boxed::HEAP;
|
||||
///
|
||||
/// fn main() {
|
||||
@ -83,7 +86,12 @@ use core::raw::{TraitObject};
|
||||
#[lang = "exchange_heap"]
|
||||
#[unstable(feature = "box_heap",
|
||||
reason = "may be renamed; uncertain about custom allocator design")]
|
||||
pub const HEAP: () = ();
|
||||
pub const HEAP: ExchangeHeapSingleton =
|
||||
ExchangeHeapSingleton { _force_singleton: () };
|
||||
|
||||
/// This the singleton type used solely for `boxed::HEAP`.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ExchangeHeapSingleton { _force_singleton: () }
|
||||
|
||||
/// A pointer type for heap allocation.
|
||||
///
|
||||
@ -91,7 +99,97 @@ pub const HEAP: () = ();
|
||||
#[lang = "owned_box"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[fundamental]
|
||||
pub struct Box<T>(Unique<T>);
|
||||
pub struct Box<T: ?Sized>(Unique<T>);
|
||||
|
||||
/// `IntermediateBox` represents uninitialized backing storage for `Box`.
|
||||
///
|
||||
/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
|
||||
/// introducing a separate `IntermediateBox<T>`; but then you hit
|
||||
/// issues when you e.g. attempt to destructure an instance of `Box`,
|
||||
/// since it is a lang item and so it gets special handling by the
|
||||
/// compiler. Easier just to make this parallel type for now.
|
||||
///
|
||||
/// FIXME (pnkfelix): Currently the `box` protocol only supports
|
||||
/// creating instances of sized types. This IntermediateBox is
|
||||
/// designed to be forward-compatible with a future protocol that
|
||||
/// supports creating instances of unsized types; that is why the type
|
||||
/// parameter has the `?Sized` generalization marker, and is also why
|
||||
/// this carries an explicit size. However, it probably does not need
|
||||
/// to carry the explicit alignment; that is just a work-around for
|
||||
/// the fact that the `align_of` intrinsic currently requires the
|
||||
/// input type to be Sized (which I do not think is strictly
|
||||
/// necessary).
|
||||
#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")]
|
||||
pub struct IntermediateBox<T: ?Sized>{
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
align: usize,
|
||||
marker: marker::PhantomData<*mut T>,
|
||||
}
|
||||
|
||||
impl<T> Place<T> for IntermediateBox<T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
unsafe { ::core::mem::transmute(self.ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
|
||||
let p = b.ptr as *mut T;
|
||||
mem::forget(b);
|
||||
mem::transmute(p)
|
||||
}
|
||||
|
||||
fn make_place<T>() -> IntermediateBox<T> {
|
||||
let size = mem::size_of::<T>();
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
let p = if size == 0 {
|
||||
heap::EMPTY as *mut u8
|
||||
} else {
|
||||
let p = unsafe {
|
||||
heap::allocate(size, align)
|
||||
};
|
||||
if p.is_null() {
|
||||
panic!("Box make_place allocation failure.");
|
||||
}
|
||||
p
|
||||
};
|
||||
|
||||
IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData }
|
||||
}
|
||||
|
||||
impl<T> BoxPlace<T> for IntermediateBox<T> {
|
||||
fn make_place() -> IntermediateBox<T> { make_place() }
|
||||
}
|
||||
|
||||
impl<T> InPlace<T> for IntermediateBox<T> {
|
||||
type Owner = Box<T>;
|
||||
unsafe fn finalize(self) -> Box<T> { finalize(self) }
|
||||
}
|
||||
|
||||
impl<T> Boxed for Box<T> {
|
||||
type Data = T;
|
||||
type Place = IntermediateBox<T>;
|
||||
unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> { finalize(b) }
|
||||
}
|
||||
|
||||
impl<T> Placer<T> for ExchangeHeapSingleton {
|
||||
type Place = IntermediateBox<T>;
|
||||
|
||||
fn make_place(self) -> IntermediateBox<T> {
|
||||
make_place()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Drop for IntermediateBox<T> {
|
||||
fn drop(&mut self) {
|
||||
if self.size > 0 {
|
||||
unsafe {
|
||||
heap::deallocate(self.ptr, self.size, self.align)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<T> {
|
||||
/// Allocates memory on the heap and then moves `x` into it.
|
||||
@ -116,7 +214,7 @@ impl<T : ?Sized> Box<T> {
|
||||
/// of `T` and releases memory. Since the way `Box` allocates and
|
||||
/// releases memory is unspecified, the only valid pointer to pass
|
||||
/// to this function is the one taken from another `Box` with
|
||||
/// `boxed::into_raw` function.
|
||||
/// `Box::into_raw` function.
|
||||
///
|
||||
/// Function is unsafe, because improper use of this function may
|
||||
/// lead to memory problems like double-free, for example if the
|
||||
@ -140,10 +238,8 @@ impl<T : ?Sized> Box<T> {
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(box_raw)]
|
||||
/// use std::boxed;
|
||||
///
|
||||
/// let seventeen = Box::new(17u32);
|
||||
/// let raw = boxed::into_raw(seventeen);
|
||||
/// let raw = Box::into_raw(seventeen);
|
||||
/// let boxed_again = unsafe { Box::from_raw(raw) };
|
||||
/// ```
|
||||
#[unstable(feature = "box_raw", reason = "may be renamed")]
|
||||
@ -201,8 +297,7 @@ impl<T: Clone> Clone for Box<T> {
|
||||
/// let y = x.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> { box {(**self).clone()} }
|
||||
|
||||
fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} }
|
||||
/// Copies `source`'s contents into `self` without creating a new allocation.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -76,9 +76,9 @@ fn deref() {
|
||||
|
||||
#[test]
|
||||
fn raw_sized() {
|
||||
let x = Box::new(17);
|
||||
let p = Box::into_raw(x);
|
||||
unsafe {
|
||||
let x = Box::new(17);
|
||||
let p = boxed::into_raw(x);
|
||||
assert_eq!(17, *p);
|
||||
*p = 19;
|
||||
let y = Box::from_raw(p);
|
||||
@ -105,9 +105,9 @@ fn raw_trait() {
|
||||
}
|
||||
}
|
||||
|
||||
let x: Box<Foo> = Box::new(Bar(17));
|
||||
let p = Box::into_raw(x);
|
||||
unsafe {
|
||||
let x: Box<Foo> = Box::new(Bar(17));
|
||||
let p = boxed::into_raw(x);
|
||||
assert_eq!(17, (*p).get());
|
||||
(*p).set(19);
|
||||
let y: Box<Foo> = Box::from_raw(p);
|
||||
|
@ -70,6 +70,8 @@
|
||||
test(no_crate_inject))]
|
||||
#![no_std]
|
||||
|
||||
// SNAP d4432b3
|
||||
#![allow(unused_features)] // until feature(placement_in_syntax) is in snap
|
||||
#![feature(allocator)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(coerce_unsized)]
|
||||
@ -82,12 +84,15 @@
|
||||
#![feature(no_std)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
#![feature(raw)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unique)]
|
||||
#![feature(unsafe_no_drop_flag, filling_drop)]
|
||||
#![feature(unsize)]
|
||||
#![feature(core_slice_ext)]
|
||||
|
||||
#![cfg_attr(test, feature(test, alloc, rustc_private, box_raw))]
|
||||
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
|
||||
@ -122,6 +127,7 @@ mod boxed { pub use std::boxed::{Box, HEAP}; }
|
||||
mod boxed_test;
|
||||
pub mod arc;
|
||||
pub mod rc;
|
||||
pub mod raw_vec;
|
||||
|
||||
/// Common out-of-memory routine
|
||||
#[cold]
|
||||
@ -133,19 +139,3 @@ pub fn oom() -> ! {
|
||||
// allocate.
|
||||
unsafe { core::intrinsics::abort() }
|
||||
}
|
||||
|
||||
// FIXME(#14344): When linking liballoc with libstd, this library will be linked
|
||||
// as an rlib (it only exists as an rlib). It turns out that an
|
||||
// optimized standard library doesn't actually use *any* symbols
|
||||
// from this library. Everything is inlined and optimized away.
|
||||
// This means that linkers will actually omit the object for this
|
||||
// file, even though it may be needed in the future.
|
||||
//
|
||||
// To get around this for now, we define a dummy symbol which
|
||||
// will never get inlined so the stdlib can call it. The stdlib's
|
||||
// reference to this symbol will cause this library's object file
|
||||
// to get linked in to libstd successfully (the linker won't
|
||||
// optimize it out).
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "issue_14344_fixme")]
|
||||
pub fn fixme_14344_be_sure_to_link_to_collections() {}
|
||||
|
453
src/liballoc/raw_vec.rs
Normal file
453
src/liballoc/raw_vec.rs
Normal file
@ -0,0 +1,453 @@
|
||||
// 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.
|
||||
|
||||
use core::ptr::Unique;
|
||||
use core::mem;
|
||||
use core::slice::{self, SliceExt};
|
||||
use heap;
|
||||
use super::oom;
|
||||
use super::boxed::Box;
|
||||
use core::ops::Drop;
|
||||
|
||||
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating a
|
||||
/// a buffer of memory on the heap without having to worry about all the corner cases
|
||||
/// involved. This type is excellent for building your own data structures like Vec and VecDeque.
|
||||
/// In particular:
|
||||
///
|
||||
/// * Produces heap::EMPTY on zero-sized types
|
||||
/// * Produces heap::EMPTY on zero-length allocations
|
||||
/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics)
|
||||
/// * Guards against 32-bit systems allocating more than isize::MAX bytes
|
||||
/// * Guards against overflowing your length
|
||||
/// * Aborts on OOM
|
||||
/// * Avoids freeing heap::EMPTY
|
||||
/// * Contains a ptr::Unique and thus endows the user with all related benefits
|
||||
///
|
||||
/// This type does not in anyway inspect the memory that it manages. When dropped it *will*
|
||||
/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec
|
||||
/// to handle the actual things *stored* inside of a RawVec.
|
||||
///
|
||||
/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types.
|
||||
/// This enables you to use capacity growing logic catch the overflows in your length
|
||||
/// that might occur with zero-sized types.
|
||||
///
|
||||
/// However this means that you need to be careful when roundtripping this type
|
||||
/// with a `Box<[T]>`: `cap()` won't yield the len. However `with_capacity`,
|
||||
/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
|
||||
/// field. This allows zero-sized types to not be special-cased by consumers of
|
||||
/// this type.
|
||||
#[unsafe_no_drop_flag]
|
||||
pub struct RawVec<T> {
|
||||
ptr: Unique<T>,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
impl<T> RawVec<T> {
|
||||
/// Creates the biggest possible RawVec without allocating. If T has positive
|
||||
/// size, then this makes a RawVec with capacity 0. If T has 0 size, then it
|
||||
/// it makes a RawVec with capacity `usize::MAX`. Useful for implementing
|
||||
/// delayed allocation.
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
// !0 is usize::MAX. This branch should be stripped at compile time.
|
||||
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
|
||||
|
||||
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
|
||||
RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap }
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a RawVec with exactly the capacity and alignment requirements
|
||||
/// for a `[T; cap]`. This is equivalent to calling RawVec::new when `cap` is 0
|
||||
/// or T is zero-sized. Note that if `T` is zero-sized this means you will *not*
|
||||
/// get a RawVec with the requested capacity!
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
|
||||
let alloc_size = cap.checked_mul(elem_size).expect("capacity overflow");
|
||||
alloc_guard(alloc_size);
|
||||
|
||||
// handles ZSTs and `cap = 0` alike
|
||||
let ptr = if alloc_size == 0 {
|
||||
heap::EMPTY as *mut u8
|
||||
} else {
|
||||
let align = mem::align_of::<T>();
|
||||
let ptr = heap::allocate(alloc_size, align);
|
||||
if ptr.is_null() { oom() }
|
||||
ptr
|
||||
};
|
||||
|
||||
RawVec { ptr: Unique::new(ptr as *mut _), cap: cap }
|
||||
}
|
||||
}
|
||||
|
||||
/// Reconstitutes a RawVec from a pointer and capacity.
|
||||
///
|
||||
/// # Undefined Behaviour
|
||||
///
|
||||
/// The ptr must be allocated, and with the given capacity. The
|
||||
/// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
|
||||
/// If the ptr and capacity come from a RawVec, then this is guaranteed.
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self {
|
||||
RawVec { ptr: Unique::new(ptr), cap: cap }
|
||||
}
|
||||
|
||||
/// Converts a `Box<[T]>` into a `RawVec<T>`.
|
||||
pub fn from_box(mut slice: Box<[T]>) -> Self {
|
||||
unsafe {
|
||||
let result = RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len());
|
||||
mem::forget(slice);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RawVec<T> {
|
||||
/// Gets a raw pointer to the start of the allocation. Note that this is
|
||||
/// heap::EMPTY if `cap = 0` or T is zero-sized. In the former case, you must
|
||||
/// be careful.
|
||||
pub fn ptr(&self) -> *mut T {
|
||||
*self.ptr
|
||||
}
|
||||
|
||||
/// Gets the capacity of the allocation.
|
||||
///
|
||||
/// This will always be `usize::MAX` if `T` is zero-sized.
|
||||
pub fn cap(&self) -> usize {
|
||||
if mem::size_of::<T>() == 0 { !0 } else { self.cap }
|
||||
}
|
||||
|
||||
/// Doubles the size of the type's backing allocation. This is common enough
|
||||
/// to want to do that it's easiest to just have a dedicated method. Slightly
|
||||
/// more efficient logic can be provided for this than the general case.
|
||||
///
|
||||
/// This function is ideal for when pushing elements one-at-a-time because
|
||||
/// you don't need to incur the costs of the more general computations
|
||||
/// reserve needs to do to guard against overflow. You do however need to
|
||||
/// manually check if your `len == cap`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if T is zero-sized on the assumption that you managed to exhaust
|
||||
/// all `usize::MAX` slots in your imaginary buffer.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct MyVec<T> {
|
||||
/// buf: RawVec<T>,
|
||||
/// len: usize,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> MyVec<T> {
|
||||
/// pub fn push(&mut self, elem: T) {
|
||||
/// if self.len == self.buf.cap() { self.buf.double(); }
|
||||
/// // double would have aborted or panicked if the len exceeded
|
||||
/// // `isize::MAX` so this is safe to do unchecked now.
|
||||
/// unsafe {
|
||||
/// ptr::write(self.buf.ptr().offset(self.len as isize), elem);
|
||||
/// }
|
||||
/// self.len += 1;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
pub fn double(&mut self) {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
|
||||
// since we set the capacity to usize::MAX when elem_size is
|
||||
// 0, getting to here necessarily means the RawVec is overfull.
|
||||
assert!(elem_size != 0, "capacity overflow");
|
||||
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
let (new_cap, ptr) = if self.cap == 0 {
|
||||
// skip to 4 because tiny Vec's are dumb; but not if that would cause overflow
|
||||
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
|
||||
let ptr = heap::allocate(new_cap * elem_size, align);
|
||||
(new_cap, ptr)
|
||||
} else {
|
||||
// Since we guarantee that we never allocate more than isize::MAX bytes,
|
||||
// `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_alloc_size = new_cap * elem_size;
|
||||
alloc_guard(new_alloc_size);
|
||||
let ptr = heap::reallocate(self.ptr() as *mut _,
|
||||
self.cap * elem_size,
|
||||
new_alloc_size,
|
||||
align);
|
||||
(new_cap, ptr)
|
||||
};
|
||||
|
||||
// If allocate or reallocate fail, we'll get `null` back
|
||||
if ptr.is_null() { oom() }
|
||||
|
||||
self.ptr = Unique::new(ptr as *mut _);
|
||||
self.cap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
/// `used_cap + needed_extra_cap` elements. If it doesn't already,
|
||||
/// will reallocate the minimum possible amount of memory necessary.
|
||||
/// Generally this will be exactly the amount of memory necessary,
|
||||
/// but in principle the allocator is free to give back more than
|
||||
/// we asked for.
|
||||
///
|
||||
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe
|
||||
/// code *you* write that relies on the behaviour of this function may break.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM
|
||||
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
// NOTE: we don't early branch on ZSTs here because we want this
|
||||
// to actually catch "asking for more than usize::MAX" in that case.
|
||||
// If we make it past the first branch then we are guaranteed to
|
||||
// panic.
|
||||
|
||||
// Don't actually need any more capacity.
|
||||
// Wrapping in case they gave a bad `used_cap`.
|
||||
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; }
|
||||
|
||||
// Nothing we can really do about these checks :(
|
||||
let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow");
|
||||
let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
|
||||
alloc_guard(new_alloc_size);
|
||||
|
||||
let ptr = if self.cap == 0 {
|
||||
heap::allocate(new_alloc_size, align)
|
||||
} else {
|
||||
heap::reallocate(self.ptr() as *mut _,
|
||||
self.cap * elem_size,
|
||||
new_alloc_size,
|
||||
align)
|
||||
};
|
||||
|
||||
// If allocate or reallocate fail, we'll get `null` back
|
||||
if ptr.is_null() { oom() }
|
||||
|
||||
self.ptr = Unique::new(ptr as *mut _);
|
||||
self.cap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
|
||||
/// enough capacity, will reallocate enough space plus comfortable slack
|
||||
/// space to get amortized `O(1)` behaviour. Will limit this behaviour
|
||||
/// if it would needlessly cause itself to panic.
|
||||
///
|
||||
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe
|
||||
/// code *you* write that relies on the behaviour of this function may break.
|
||||
///
|
||||
/// This is ideal for implementing a bulk-push operation like `extend`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct MyVec<T> {
|
||||
/// buf: RawVec<T>,
|
||||
/// len: usize,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> MyVec<T> {
|
||||
/// pub fn push_all(&mut self, elems: &[T]) {
|
||||
/// self.buf.reserve(self.len, elems.len());
|
||||
/// // reserve would have aborted or panicked if the len exceeded
|
||||
/// // `isize::MAX` so this is safe to do unchecked now.
|
||||
/// for x in elems {
|
||||
/// unsafe {
|
||||
/// ptr::write(self.buf.ptr().offset(self.len as isize), x.clone());
|
||||
/// }
|
||||
/// self.len += 1;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
|
||||
unsafe {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
// NOTE: we don't early branch on ZSTs here because we want this
|
||||
// to actually catch "asking for more than usize::MAX" in that case.
|
||||
// If we make it past the first branch then we are guaranteed to
|
||||
// panic.
|
||||
|
||||
// Don't actually need any more capacity.
|
||||
// Wrapping in case they give a bas `used_cap`
|
||||
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; }
|
||||
|
||||
// Nothing we can really do about these checks :(
|
||||
let new_cap = used_cap.checked_add(needed_extra_cap)
|
||||
.and_then(|cap| cap.checked_mul(2))
|
||||
.expect("capacity overflow");
|
||||
let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow");
|
||||
// FIXME: may crash and burn on over-reserve
|
||||
alloc_guard(new_alloc_size);
|
||||
|
||||
let ptr = if self.cap == 0 {
|
||||
heap::allocate(new_alloc_size, align)
|
||||
} else {
|
||||
heap::reallocate(self.ptr() as *mut _,
|
||||
self.cap * elem_size,
|
||||
new_alloc_size,
|
||||
align)
|
||||
};
|
||||
|
||||
// If allocate or reallocate fail, we'll get `null` back
|
||||
if ptr.is_null() { oom() }
|
||||
|
||||
self.ptr = Unique::new(ptr as *mut _);
|
||||
self.cap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
/// Shrinks the allocation down to the specified amount. If the given amount
|
||||
/// is 0, actually completely deallocates.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the given amount is *larger* than the current capacity.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM.
|
||||
pub fn shrink_to_fit(&mut self, amount: usize) {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
// Set the `cap` because they might be about to promote to a `Box<[T]>`
|
||||
if elem_size == 0 {
|
||||
self.cap = amount;
|
||||
return;
|
||||
}
|
||||
|
||||
// This check is my waterloo; it's the only thing Vec wouldn't have to do.
|
||||
assert!(self.cap >= amount, "Tried to shrink to a larger capacity");
|
||||
|
||||
if amount == 0 {
|
||||
mem::replace(self, RawVec::new());
|
||||
} else if self.cap != amount {
|
||||
unsafe {
|
||||
// Overflow check is unnecessary as the vector is already at
|
||||
// least this large.
|
||||
let ptr = heap::reallocate(self.ptr() as *mut _,
|
||||
self.cap * elem_size,
|
||||
amount * elem_size,
|
||||
align);
|
||||
if ptr.is_null() { oom() }
|
||||
self.ptr = Unique::new(ptr as *mut _);
|
||||
}
|
||||
self.cap = amount;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the entire buffer into `Box<[T]>`.
|
||||
///
|
||||
/// While it is not *strictly* Undefined Behaviour to call
|
||||
/// this procedure while some of the RawVec is unintialized,
|
||||
/// it cetainly makes it trivial to trigger it.
|
||||
///
|
||||
/// Note that this will correctly reconstitute any `cap` changes
|
||||
/// that may have been performed. (see description of type for details)
|
||||
pub unsafe fn into_box(self) -> Box<[T]> {
|
||||
// NOTE: not calling `cap()` here, actually using the real `cap` field!
|
||||
let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
|
||||
let output: Box<[T]> = Box::from_raw(slice);
|
||||
mem::forget(self);
|
||||
output
|
||||
}
|
||||
|
||||
/// This is a stupid name in the hopes that someone will find this in the
|
||||
/// not too distant future and remove it with the rest of
|
||||
/// #[unsafe_no_drop_flag]
|
||||
pub fn unsafe_no_drop_flag_needs_drop(&self) -> bool {
|
||||
self.cap != mem::POST_DROP_USIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for RawVec<T> {
|
||||
/// Frees the memory owned by the RawVec *without* trying to Drop its contents.
|
||||
fn drop(&mut self) {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
if elem_size != 0 && self.cap != 0 && self.unsafe_no_drop_flag_needs_drop() {
|
||||
let align = mem::align_of::<T>();
|
||||
|
||||
let num_bytes = elem_size * self.cap;
|
||||
unsafe {
|
||||
heap::deallocate(*self.ptr as *mut _, num_bytes, align);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// We need to guarantee the following:
|
||||
// * We don't ever allocate `> isize::MAX` byte-size objects
|
||||
// * We don't overflow `usize::MAX` and actually allocate too little
|
||||
//
|
||||
// On 64-bit we just need to check for overflow since trying to allocate
|
||||
// `> isize::MAX` bytes will surely fail. On 32-bit we need to add an extra
|
||||
// guard for this in case we're running on a platform which can use all 4GB in
|
||||
// user-space. e.g. PAE or x32
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn alloc_guard(_alloc_size: usize) { }
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn alloc_guard(alloc_size: usize) {
|
||||
assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow");
|
||||
}
|
@ -162,7 +162,7 @@ use core::fmt;
|
||||
use core::hash::{Hasher, Hash};
|
||||
use core::intrinsics::{assume, drop_in_place};
|
||||
use core::marker::{self, Unsize};
|
||||
use core::mem::{self, min_align_of, size_of, min_align_of_val, size_of_val, forget};
|
||||
use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget};
|
||||
use core::nonzero::NonZero;
|
||||
use core::ops::{CoerceUnsized, Deref};
|
||||
use core::ptr;
|
||||
@ -246,7 +246,7 @@ impl<T> Rc<T> {
|
||||
// destruct the box and skip our Drop
|
||||
// we can ignore the refcounts because we know we're unique
|
||||
deallocate(*rc._ptr as *mut u8, size_of::<RcBox<T>>(),
|
||||
min_align_of::<RcBox<T>>());
|
||||
align_of::<RcBox<T>>());
|
||||
forget(rc);
|
||||
Ok(val)
|
||||
}
|
||||
@ -496,7 +496,7 @@ impl<T: ?Sized> Drop for Rc<T> {
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8,
|
||||
size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -734,6 +734,8 @@ pub struct Weak<T: ?Sized> {
|
||||
impl<T: ?Sized> !marker::Send for Weak<T> {}
|
||||
impl<T: ?Sized> !marker::Sync for Weak<T> {}
|
||||
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
|
||||
|
||||
#[unstable(feature = "rc_weak",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
@ -805,7 +807,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
// the strong pointers have disappeared.
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8, size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ impl<'longer_than_self> Arena<'longer_than_self> {
|
||||
fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
|
||||
unsafe {
|
||||
let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>());
|
||||
mem::align_of::<T>());
|
||||
let ptr = ptr as *mut T;
|
||||
ptr::write(&mut (*ptr), op());
|
||||
return &mut *ptr;
|
||||
@ -300,7 +300,7 @@ impl<'longer_than_self> Arena<'longer_than_self> {
|
||||
let tydesc = get_tydesc::<T>();
|
||||
let (ty_ptr, ptr) =
|
||||
self.alloc_noncopy_inner(mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>());
|
||||
mem::align_of::<T>());
|
||||
let ty_ptr = ty_ptr as *mut usize;
|
||||
let ptr = ptr as *mut T;
|
||||
// Write in our tydesc along with a bit indicating that it
|
||||
@ -393,7 +393,7 @@ struct TypedArenaChunk<T> {
|
||||
|
||||
fn calculate_size<T>(capacity: usize) -> usize {
|
||||
let mut size = mem::size_of::<TypedArenaChunk<T>>();
|
||||
size = round_up(size, mem::min_align_of::<T>());
|
||||
size = round_up(size, mem::align_of::<T>());
|
||||
let elem_size = mem::size_of::<T>();
|
||||
let elems_size = elem_size.checked_mul(capacity).unwrap();
|
||||
size = size.checked_add(elems_size).unwrap();
|
||||
@ -405,7 +405,7 @@ impl<T> TypedArenaChunk<T> {
|
||||
unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize)
|
||||
-> *mut TypedArenaChunk<T> {
|
||||
let size = calculate_size::<T>(capacity);
|
||||
let chunk = allocate(size, mem::min_align_of::<TypedArenaChunk<T>>())
|
||||
let chunk = allocate(size, mem::align_of::<TypedArenaChunk<T>>())
|
||||
as *mut TypedArenaChunk<T>;
|
||||
if chunk.is_null() { alloc::oom() }
|
||||
(*chunk).next = next;
|
||||
@ -431,7 +431,7 @@ impl<T> TypedArenaChunk<T> {
|
||||
let size = calculate_size::<T>(self.capacity);
|
||||
let self_ptr: *mut TypedArenaChunk<T> = self;
|
||||
deallocate(self_ptr as *mut u8, size,
|
||||
mem::min_align_of::<TypedArenaChunk<T>>());
|
||||
mem::align_of::<TypedArenaChunk<T>>());
|
||||
if !next.is_null() {
|
||||
let capacity = (*next).capacity;
|
||||
(*next).destroy(capacity);
|
||||
@ -444,7 +444,7 @@ impl<T> TypedArenaChunk<T> {
|
||||
let this: *const TypedArenaChunk<T> = self;
|
||||
unsafe {
|
||||
mem::transmute(round_up(this.offset(1) as usize,
|
||||
mem::min_align_of::<T>()))
|
||||
mem::align_of::<T>()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deprecated(reason = "BitVec and BitSet have been migrated to cargo as bit-vec and bit-set",
|
||||
since = "1.3.0")]
|
||||
#![unstable(feature = "collections", reason = "deprecated")]
|
||||
#![allow(deprecated)]
|
||||
|
||||
// FIXME(Gankro): BitVec and BitSet are very tightly coupled. Ideally (for
|
||||
// maintenance), they should be in separate files/modules, with BitSet only
|
||||
// using BitVec's public API. This will be hard for performance though, because
|
||||
@ -278,7 +283,7 @@ impl BitVec {
|
||||
pub fn from_elem(nbits: usize, bit: bool) -> BitVec {
|
||||
let nblocks = blocks_for_bits(nbits);
|
||||
let mut bit_vec = BitVec {
|
||||
storage: repeat(if bit { !0 } else { 0 }).take(nblocks).collect(),
|
||||
storage: vec![if bit { !0 } else { 0 }; nblocks],
|
||||
nbits: nbits
|
||||
};
|
||||
bit_vec.fix_last_block();
|
||||
|
@ -215,7 +215,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
|
||||
impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
/// Acquires a mutable reference to the owned form of the data.
|
||||
///
|
||||
/// Copies the data if it is not already owned.
|
||||
/// Clones the data if it is not already owned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -241,7 +241,7 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
|
||||
/// Extracts the owned data.
|
||||
///
|
||||
/// Copies the data if it is not already owned.
|
||||
/// Clones the data if it is not already owned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -163,12 +163,12 @@ fn test_offset_calculation() {
|
||||
}
|
||||
|
||||
fn calculate_allocation_generic<K, V>(capacity: usize, is_leaf: bool) -> (usize, usize) {
|
||||
let (keys_size, keys_align) = (capacity * mem::size_of::<K>(), mem::min_align_of::<K>());
|
||||
let (vals_size, vals_align) = (capacity * mem::size_of::<V>(), mem::min_align_of::<V>());
|
||||
let (keys_size, keys_align) = (capacity * mem::size_of::<K>(), mem::align_of::<K>());
|
||||
let (vals_size, vals_align) = (capacity * mem::size_of::<V>(), mem::align_of::<V>());
|
||||
let (edges_size, edges_align) = if is_leaf {
|
||||
(0, 1)
|
||||
} else {
|
||||
((capacity + 1) * mem::size_of::<Node<K, V>>(), mem::min_align_of::<Node<K, V>>())
|
||||
((capacity + 1) * mem::size_of::<Node<K, V>>(), mem::align_of::<Node<K, V>>())
|
||||
};
|
||||
|
||||
calculate_allocation(
|
||||
@ -181,11 +181,11 @@ fn calculate_allocation_generic<K, V>(capacity: usize, is_leaf: bool) -> (usize,
|
||||
fn calculate_offsets_generic<K, V>(capacity: usize, is_leaf: bool) -> (usize, usize) {
|
||||
let keys_size = capacity * mem::size_of::<K>();
|
||||
let vals_size = capacity * mem::size_of::<V>();
|
||||
let vals_align = mem::min_align_of::<V>();
|
||||
let vals_align = mem::align_of::<V>();
|
||||
let edges_align = if is_leaf {
|
||||
1
|
||||
} else {
|
||||
mem::min_align_of::<Node<K, V>>()
|
||||
mem::align_of::<Node<K, V>>()
|
||||
};
|
||||
|
||||
calculate_offsets(
|
||||
|
@ -128,15 +128,15 @@
|
||||
//! This allows multiple actual types to be formatted via `{:x}` (like `i8` as
|
||||
//! well as `isize`). The current mapping of types to traits is:
|
||||
//!
|
||||
//! * *nothing* ⇒ `Display`
|
||||
//! * `?` ⇒ `Debug`
|
||||
//! * `o` ⇒ `Octal`
|
||||
//! * `x` ⇒ `LowerHex`
|
||||
//! * `X` ⇒ `UpperHex`
|
||||
//! * `p` ⇒ `Pointer`
|
||||
//! * `b` ⇒ `Binary`
|
||||
//! * `e` ⇒ `LowerExp`
|
||||
//! * `E` ⇒ `UpperExp`
|
||||
//! * *nothing* ⇒ [`Display`](trait.Display.html)
|
||||
//! * `?` ⇒ [`Debug`](trait.Debug.html)
|
||||
//! * `o` ⇒ [`Octal`](trait.Octal.html)
|
||||
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
|
||||
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
|
||||
//! * `p` ⇒ [`Pointer`](trait.Pointer.html)
|
||||
//! * `b` ⇒ [`Binary`](trait.Binary.html)
|
||||
//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html)
|
||||
//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html)
|
||||
//!
|
||||
//! What this means is that any type of argument which implements the
|
||||
//! `fmt::Binary` trait can then be formatted with `{:b}`. Implementations
|
||||
@ -367,11 +367,11 @@
|
||||
//! should always be printed.
|
||||
//! * '-' - Currently not used
|
||||
//! * '#' - This flag is indicates that the "alternate" form of printing should
|
||||
//! be used. For array slices, the alternate form omits the brackets.
|
||||
//! For the integer formatting traits, the alternate forms are:
|
||||
//! be used. The alternate forms are:
|
||||
//! * `#?` - pretty-print the `Debug` formatting
|
||||
//! * `#x` - precedes the argument with a "0x"
|
||||
//! * `#X` - precedes the argument with a "0x"
|
||||
//! * `#t` - precedes the argument with a "0b"
|
||||
//! * `#b` - precedes the argument with a "0b"
|
||||
//! * `#o` - precedes the argument with a "0o"
|
||||
//! * '0' - This is used to indicate for integer formats that the padding should
|
||||
//! both be done with a `0` character as well as be sign-aware. A format
|
||||
@ -408,19 +408,20 @@
|
||||
//!
|
||||
//! There are three possible ways to specify the desired `precision`:
|
||||
//!
|
||||
//! There are three possible ways to specify the desired `precision`:
|
||||
//! 1. An integer `.N`,
|
||||
//! 2. an integer followed by dollar sign `.N$`, or
|
||||
//! 3. an asterisk `.*`.
|
||||
//! 1. An integer `.N`:
|
||||
//!
|
||||
//! The first specification, `.N`, means the integer `N` itself is the precision.
|
||||
//! the integer `N` itself is the precision.
|
||||
//!
|
||||
//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision.
|
||||
//! 2. An integer followed by dollar sign `.N$`:
|
||||
//!
|
||||
//! Finally, `.*` means that this `{...}` is associated with *two* format inputs rather than one:
|
||||
//! the first input holds the `usize` precision, and the second holds the value to print. Note
|
||||
//! that in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part
|
||||
//! refers to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
|
||||
//! use format *argument* `N` (which must be a `usize`) as the precision.
|
||||
//!
|
||||
//! 3. An asterisk `.*`:
|
||||
//!
|
||||
//! `.*` means that this `{...}` is associated with *two* format inputs rather than one: the
|
||||
//! first input holds the `usize` precision, and the second holds the value to print. Note that
|
||||
//! in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
|
||||
//! to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
|
||||
//!
|
||||
//! For example, these:
|
||||
//!
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_raw)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(core)]
|
||||
#![feature(core_intrinsics)]
|
||||
@ -77,7 +76,9 @@ extern crate alloc;
|
||||
#[cfg(test)] extern crate test;
|
||||
|
||||
pub use binary_heap::BinaryHeap;
|
||||
#[allow(deprecated)]
|
||||
pub use bit_vec::BitVec;
|
||||
#[allow(deprecated)]
|
||||
pub use bit_set::BitSet;
|
||||
pub use btree_map::BTreeMap;
|
||||
pub use btree_set::BTreeSet;
|
||||
@ -111,11 +112,13 @@ pub mod vec_map;
|
||||
|
||||
#[unstable(feature = "bitvec", reason = "RFC 509")]
|
||||
pub mod bit_vec {
|
||||
#![allow(deprecated)]
|
||||
pub use bit::{BitVec, Iter};
|
||||
}
|
||||
|
||||
#[unstable(feature = "bitset", reason = "RFC 509")]
|
||||
pub mod bit_set {
|
||||
#![allow(deprecated)]
|
||||
pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference};
|
||||
pub use bit::SetIter as Iter;
|
||||
}
|
||||
@ -130,12 +133,6 @@ pub mod btree_set {
|
||||
pub use btree::set::*;
|
||||
}
|
||||
|
||||
|
||||
// FIXME(#14344) this shouldn't be necessary
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "issue_14344_fixme")]
|
||||
pub fn fixme_14344_be_sure_to_link_to_collections() {}
|
||||
|
||||
#[cfg(not(test))]
|
||||
mod std {
|
||||
pub use core::ops; // RangeFull
|
||||
|
@ -8,9 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Utilities for slice manipulation
|
||||
//! A dynamically-sized view into a contiguous sequence, `[T]`.
|
||||
//!
|
||||
//! The `slice` module contains useful code to help work with slice values.
|
||||
//! Slices are a view into a block of memory represented as a pointer and a
|
||||
//! length.
|
||||
//!
|
||||
@ -78,7 +77,8 @@
|
||||
//! iterators.
|
||||
//! * Further methods that return iterators are `.split()`, `.splitn()`,
|
||||
//! `.chunks()`, `.windows()` and more.
|
||||
#![doc(primitive = "slice")]
|
||||
//!
|
||||
//! *[See also the slice primitive type](../primitive.slice.html).*
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
// Many of the usings in this module are only used in the test configuration.
|
||||
@ -282,34 +282,65 @@ impl<T> [T] {
|
||||
|
||||
/// Returns all but the first element of a slice.
|
||||
#[unstable(feature = "slice_extras", reason = "likely to be renamed")]
|
||||
#[deprecated(since = "1.3.0", reason = "superseded by split_first")]
|
||||
#[inline]
|
||||
pub fn tail(&self) -> &[T] {
|
||||
core_slice::SliceExt::tail(self)
|
||||
}
|
||||
|
||||
/// Returns the first and all the rest of the elements of a slice.
|
||||
#[unstable(feature = "slice_splits", reason = "new API")]
|
||||
#[inline]
|
||||
pub fn split_first(&self) -> Option<(&T, &[T])> {
|
||||
core_slice::SliceExt::split_first(self)
|
||||
}
|
||||
|
||||
/// Returns all but the first element of a mutable slice
|
||||
#[unstable(feature = "slice_extras",
|
||||
reason = "likely to be renamed or removed")]
|
||||
#[unstable(feature = "slice_extras", reason = "likely to be renamed or removed")]
|
||||
#[deprecated(since = "1.3.0", reason = "superseded by split_first_mut")]
|
||||
#[inline]
|
||||
pub fn tail_mut(&mut self) -> &mut [T] {
|
||||
core_slice::SliceExt::tail_mut(self)
|
||||
}
|
||||
|
||||
/// Returns the first and all the rest of the elements of a slice.
|
||||
#[unstable(feature = "slice_splits", reason = "new API")]
|
||||
#[inline]
|
||||
pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
|
||||
core_slice::SliceExt::split_first_mut(self)
|
||||
}
|
||||
|
||||
/// Returns all but the last element of a slice.
|
||||
#[unstable(feature = "slice_extras", reason = "likely to be renamed")]
|
||||
#[deprecated(since = "1.3.0", reason = "superseded by split_last")]
|
||||
#[inline]
|
||||
pub fn init(&self) -> &[T] {
|
||||
core_slice::SliceExt::init(self)
|
||||
}
|
||||
|
||||
/// Returns the last and all the rest of the elements of a slice.
|
||||
#[unstable(feature = "slice_splits", reason = "new API")]
|
||||
#[inline]
|
||||
pub fn split_last(&self) -> Option<(&T, &[T])> {
|
||||
core_slice::SliceExt::split_last(self)
|
||||
|
||||
}
|
||||
|
||||
/// Returns all but the last element of a mutable slice
|
||||
#[unstable(feature = "slice_extras",
|
||||
reason = "likely to be renamed or removed")]
|
||||
#[unstable(feature = "slice_extras", reason = "likely to be renamed or removed")]
|
||||
#[deprecated(since = "1.3.0", reason = "superseded by split_last_mut")]
|
||||
#[inline]
|
||||
pub fn init_mut(&mut self) -> &mut [T] {
|
||||
core_slice::SliceExt::init_mut(self)
|
||||
}
|
||||
|
||||
/// Returns the last and all the rest of the elements of a slice.
|
||||
#[unstable(feature = "slice_splits", since = "1.3.0")]
|
||||
#[inline]
|
||||
pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
|
||||
core_slice::SliceExt::split_last_mut(self)
|
||||
}
|
||||
|
||||
/// Returns the last element of a slice, or `None` if it is empty.
|
||||
///
|
||||
/// # Examples
|
||||
@ -1025,6 +1056,17 @@ pub trait SliceConcatExt<T: ?Sized> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn concat(&self) -> Self::Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`, placing a
|
||||
/// given separator between each.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(["hello", "world"].join(" "), "hello world");
|
||||
/// ```
|
||||
#[stable(feature = "rename_connect_to_join", since = "1.3.0")]
|
||||
fn join(&self, sep: &T) -> Self::Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`, placing a
|
||||
/// given separator between each.
|
||||
///
|
||||
@ -1034,6 +1076,7 @@ pub trait SliceConcatExt<T: ?Sized> {
|
||||
/// assert_eq!(["hello", "world"].connect(" "), "hello world");
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[deprecated(since = "1.3.0", reason = "renamed to join")]
|
||||
fn connect(&self, sep: &T) -> Self::Output;
|
||||
}
|
||||
|
||||
@ -1049,7 +1092,7 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
|
||||
result
|
||||
}
|
||||
|
||||
fn connect(&self, sep: &T) -> Vec<T> {
|
||||
fn join(&self, sep: &T) -> Vec<T> {
|
||||
let size = self.iter().fold(0, |acc, v| acc + v.borrow().len());
|
||||
let mut result = Vec::with_capacity(size + self.len());
|
||||
let mut first = true;
|
||||
@ -1059,6 +1102,10 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn connect(&self, sep: &T) -> Vec<T> {
|
||||
self.join(sep)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that yields the element swaps needed to produce
|
||||
|
@ -8,43 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Unicode string manipulation (the `str` type).
|
||||
//! Unicode string slices
|
||||
//!
|
||||
//! Rust's `str` type is one of the core primitive types of the language. `&str`
|
||||
//! is the borrowed string type. This type of string can only be created from
|
||||
//! other strings, unless it is a `&'static str` (see below). It is not possible
|
||||
//! to move out of borrowed strings because they are owned elsewhere.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Here's some code that uses a `&str`:
|
||||
//!
|
||||
//! ```
|
||||
//! let s = "Hello, world.";
|
||||
//! ```
|
||||
//!
|
||||
//! This `&str` is a `&'static str`, which is the type of string literals.
|
||||
//! They're `'static` because literals are available for the entire lifetime of
|
||||
//! the program.
|
||||
//!
|
||||
//! You can get a non-`'static` `&str` by taking a slice of a `String`:
|
||||
//!
|
||||
//! ```
|
||||
//! let some_string = "Hello, world.".to_string();
|
||||
//! let s = &some_string;
|
||||
//! ```
|
||||
//!
|
||||
//! # Representation
|
||||
//!
|
||||
//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as
|
||||
//! a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are
|
||||
//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are
|
||||
//! not null-terminated and can thus contain null bytes.
|
||||
//!
|
||||
//! The actual representation of `str`s have direct mappings to slices: `&str`
|
||||
//! is the same as `&[u8]`.
|
||||
//! *[See also the `str` primitive type](../primitive.str.html).*
|
||||
|
||||
|
||||
#![doc(primitive = "str")]
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
// Many of the usings in this module are only used in the test configuration.
|
||||
@ -61,6 +29,7 @@ use core::result::Result;
|
||||
use core::str as core_str;
|
||||
use core::str::pattern::Pattern;
|
||||
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
|
||||
use core::mem;
|
||||
use rustc_unicode::str::{UnicodeStr, Utf16Encoder};
|
||||
|
||||
use vec_deque::VecDeque;
|
||||
@ -69,6 +38,7 @@ use string::String;
|
||||
use rustc_unicode;
|
||||
use vec::Vec;
|
||||
use slice::SliceConcatExt;
|
||||
use boxed::Box;
|
||||
|
||||
pub use core::str::{FromStr, Utf8Error};
|
||||
pub use core::str::{Lines, LinesAny, CharRange};
|
||||
@ -82,10 +52,6 @@ pub use core::str::{from_utf8_unchecked, ParseBoolError};
|
||||
pub use rustc_unicode::str::{SplitWhitespace, Words, Graphemes, GraphemeIndices};
|
||||
pub use core::str::pattern;
|
||||
|
||||
/*
|
||||
Section: Creating a string
|
||||
*/
|
||||
|
||||
impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
|
||||
type Output = String;
|
||||
|
||||
@ -105,7 +71,7 @@ impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
|
||||
result
|
||||
}
|
||||
|
||||
fn connect(&self, sep: &str) -> String {
|
||||
fn join(&self, sep: &str) -> String {
|
||||
if self.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
@ -132,11 +98,11 @@ impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Section: Iterators
|
||||
*/
|
||||
fn connect(&self, sep: &str) -> String {
|
||||
self.join(sep)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions used for Unicode normalization
|
||||
fn canonical_sort(comb: &mut [(char, u8)]) {
|
||||
@ -382,10 +348,6 @@ impl<'a> Iterator for Utf16Units<'a> {
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.encoder.size_hint() }
|
||||
}
|
||||
|
||||
/*
|
||||
Section: Misc
|
||||
*/
|
||||
|
||||
// Return the initial codepoint accumulator for the first byte.
|
||||
// The first byte is special, only want bottom 5 bits for width 2, 4 bits
|
||||
// for width 3, and 3 bits for width 4
|
||||
@ -414,15 +376,6 @@ impl ToOwned for str {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Section: CowString
|
||||
*/
|
||||
|
||||
/*
|
||||
Section: Trait implementations
|
||||
*/
|
||||
|
||||
|
||||
/// Any string that can be represented as a slice.
|
||||
#[lang = "str"]
|
||||
#[cfg(not(test))]
|
||||
@ -483,9 +436,7 @@ impl str {
|
||||
/// considered to be
|
||||
/// boundaries.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `index` is greater than `self.len()`.
|
||||
/// Returns `false` if `index` is greater than `self.len()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -549,7 +500,7 @@ impl str {
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// Caller must check both UTF-8 character boundaries and the boundaries
|
||||
/// Caller must check both UTF-8 sequence boundaries and the boundaries
|
||||
/// of the entire slice as
|
||||
/// well.
|
||||
///
|
||||
@ -567,15 +518,24 @@ impl str {
|
||||
core_str::StrExt::slice_unchecked(self, begin, end)
|
||||
}
|
||||
|
||||
/// Returns a slice of the string from the character range [`begin`..`end`).
|
||||
/// Takes a bytewise mutable slice from a string.
|
||||
///
|
||||
/// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`.
|
||||
#[unstable(feature = "str_slice_mut", reason = "recently added")]
|
||||
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
|
||||
core_str::StrExt::slice_mut_unchecked(self, begin, end)
|
||||
}
|
||||
|
||||
/// Returns a slice of the string from the range [`begin`..`end`) where indices
|
||||
/// are counted in code points.
|
||||
///
|
||||
/// That is, start at the `begin`-th code point of the string and continue
|
||||
/// to the `end`-th code point. This does not detect or handle edge cases
|
||||
/// such as leaving a combining character as the first code point of the
|
||||
/// such as leaving a combining character as the first `char` of the
|
||||
/// string.
|
||||
///
|
||||
/// Due to the design of UTF-8, this operation is `O(end)`. Use slicing
|
||||
/// syntax if you want to use byte indices rather than codepoint indices.
|
||||
/// syntax if you want to use `O(1)` byte indices instead.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -597,18 +557,18 @@ impl str {
|
||||
core_str::StrExt::slice_chars(self, begin, end)
|
||||
}
|
||||
|
||||
/// Given a byte position, return the next char and its index.
|
||||
/// Given a byte position, return the next code point and its index.
|
||||
///
|
||||
/// This can be used to iterate over the Unicode characters of a string.
|
||||
/// This can be used to iterate over the Unicode code points of a string.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `i` is greater than or equal to the length of the string.
|
||||
/// If `i` is not the index of the beginning of a valid UTF-8 character.
|
||||
/// If `i` is not the index of the beginning of a valid UTF-8 sequence.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This example manually iterates through the characters of a string;
|
||||
/// This example manually iterates through the code points of a string;
|
||||
/// this should normally be
|
||||
/// done by `.chars()` or `.char_indices()`.
|
||||
///
|
||||
@ -616,7 +576,7 @@ impl str {
|
||||
/// # #![feature(str_char, core)]
|
||||
/// use std::str::CharRange;
|
||||
///
|
||||
/// let s = "中华Việt Nam";
|
||||
/// let s = "中华Việt Nam";
|
||||
/// let mut i = 0;
|
||||
/// while i < s.len() {
|
||||
/// let CharRange {ch, next} = s.char_range_at(i);
|
||||
@ -632,12 +592,14 @@ impl str {
|
||||
/// 3: 华
|
||||
/// 6: V
|
||||
/// 7: i
|
||||
/// 8: ệ
|
||||
/// 11: t
|
||||
/// 12:
|
||||
/// 13: N
|
||||
/// 14: a
|
||||
/// 15: m
|
||||
/// 8: e
|
||||
/// 9: ̣
|
||||
/// 11: ̂
|
||||
/// 13: t
|
||||
/// 14:
|
||||
/// 15: N
|
||||
/// 16: a
|
||||
/// 17: m
|
||||
/// ```
|
||||
#[unstable(feature = "str_char",
|
||||
reason = "often replaced by char_indices, this method may \
|
||||
@ -649,18 +611,21 @@ impl str {
|
||||
|
||||
/// Given a byte position, return the previous `char` and its position.
|
||||
///
|
||||
/// This function can be used to iterate over a Unicode string in reverse.
|
||||
/// This function can be used to iterate over a Unicode code points in reverse.
|
||||
///
|
||||
/// Note that Unicode has many features, such as combining marks, ligatures,
|
||||
/// and direction marks, that need to be taken into account to correctly reverse a string.
|
||||
///
|
||||
/// Returns 0 for next index if called on start index 0.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `i` is greater than the length of the string.
|
||||
/// If `i` is not an index following a valid UTF-8 character.
|
||||
/// If `i` is not an index following a valid UTF-8 sequence.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This example manually iterates through the characters of a string;
|
||||
/// This example manually iterates through the code points of a string;
|
||||
/// this should normally be
|
||||
/// done by `.chars().rev()` or `.char_indices()`.
|
||||
///
|
||||
@ -668,7 +633,7 @@ impl str {
|
||||
/// # #![feature(str_char, core)]
|
||||
/// use std::str::CharRange;
|
||||
///
|
||||
/// let s = "中华Việt Nam";
|
||||
/// let s = "中华Việt Nam";
|
||||
/// let mut i = s.len();
|
||||
/// while i > 0 {
|
||||
/// let CharRange {ch, next} = s.char_range_at_reverse(i);
|
||||
@ -680,12 +645,14 @@ impl str {
|
||||
/// This outputs:
|
||||
///
|
||||
/// ```text
|
||||
/// 16: m
|
||||
/// 15: a
|
||||
/// 14: N
|
||||
/// 13:
|
||||
/// 12: t
|
||||
/// 11: ệ
|
||||
/// 18: m
|
||||
/// 17: a
|
||||
/// 16: N
|
||||
/// 15:
|
||||
/// 14: t
|
||||
/// 13: ̂
|
||||
/// 11: ̣
|
||||
/// 9: e
|
||||
/// 8: i
|
||||
/// 7: V
|
||||
/// 6: 华
|
||||
@ -704,7 +671,7 @@ impl str {
|
||||
/// # Panics
|
||||
///
|
||||
/// If `i` is greater than or equal to the length of the string.
|
||||
/// If `i` is not the index of the beginning of a valid UTF-8 character.
|
||||
/// If `i` is not the index of the beginning of a valid UTF-8 sequence.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -713,6 +680,7 @@ impl str {
|
||||
/// let s = "abπc";
|
||||
/// assert_eq!(s.char_at(1), 'b');
|
||||
/// assert_eq!(s.char_at(2), 'π');
|
||||
/// assert_eq!(s.char_at(4), 'c');
|
||||
/// ```
|
||||
#[unstable(feature = "str_char",
|
||||
reason = "frequently replaced by the chars() iterator, this \
|
||||
@ -730,7 +698,7 @@ impl str {
|
||||
/// # Panics
|
||||
///
|
||||
/// If `i` is greater than the length of the string.
|
||||
/// If `i` is not an index following a valid UTF-8 character.
|
||||
/// If `i` is not an index following a valid UTF-8 sequence.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -739,6 +707,7 @@ impl str {
|
||||
/// let s = "abπc";
|
||||
/// assert_eq!(s.char_at_reverse(1), 'a');
|
||||
/// assert_eq!(s.char_at_reverse(2), 'b');
|
||||
/// assert_eq!(s.char_at_reverse(3), 'π');
|
||||
/// ```
|
||||
#[unstable(feature = "str_char",
|
||||
reason = "see char_at for more details, but reverse semantics \
|
||||
@ -748,28 +717,30 @@ impl str {
|
||||
core_str::StrExt::char_at_reverse(self, i)
|
||||
}
|
||||
|
||||
/// Retrieves the first character from a `&str` and returns it.
|
||||
/// Retrieves the first code point from a `&str` and returns it.
|
||||
///
|
||||
/// Note that a single Unicode character (grapheme cluster)
|
||||
/// can be composed of multiple `char`s.
|
||||
///
|
||||
/// This does not allocate a new string; instead, it returns a slice that
|
||||
/// points one character
|
||||
/// beyond the character that was shifted.
|
||||
/// points one code point beyond the code point that was shifted.
|
||||
///
|
||||
/// If the slice does not contain any characters, None is returned instead.
|
||||
/// `None` is returned if the slice is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_char)]
|
||||
/// let s = "Löwe 老虎 Léopard";
|
||||
/// let s = "Łódź"; // \u{141}o\u{301}dz\u{301}
|
||||
/// let (c, s1) = s.slice_shift_char().unwrap();
|
||||
///
|
||||
/// assert_eq!(c, 'L');
|
||||
/// assert_eq!(s1, "öwe 老虎 Léopard");
|
||||
/// assert_eq!(c, 'Ł');
|
||||
/// assert_eq!(s1, "ódź");
|
||||
///
|
||||
/// let (c, s2) = s1.slice_shift_char().unwrap();
|
||||
///
|
||||
/// assert_eq!(c, 'ö');
|
||||
/// assert_eq!(s2, "we 老虎 Léopard");
|
||||
/// assert_eq!(c, 'o');
|
||||
/// assert_eq!(s2, "\u{301}dz\u{301}");
|
||||
/// ```
|
||||
#[unstable(feature = "str_char",
|
||||
reason = "awaiting conventions about shifting and slices and \
|
||||
@ -782,18 +753,18 @@ impl str {
|
||||
/// Divide one string slice into two at an index.
|
||||
///
|
||||
/// The index `mid` is a byte offset from the start of the string
|
||||
/// that must be on a character boundary.
|
||||
/// that must be on a `char` boundary.
|
||||
///
|
||||
/// Return slices `&self[..mid]` and `&self[mid..]`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid` is beyond the last character of the string,
|
||||
/// or if it is not on a character boundary.
|
||||
/// Panics if `mid` is beyond the last code point of the string,
|
||||
/// or if it is not on a `char` boundary.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(collections)]
|
||||
/// # #![feature(str_split_at)]
|
||||
/// let s = "Löwe 老虎 Léopard";
|
||||
/// let first_space = s.find(' ').unwrap_or(s.len());
|
||||
/// let (a, b) = s.split_at(first_space);
|
||||
@ -802,31 +773,51 @@ impl str {
|
||||
/// assert_eq!(b, " 老虎 Léopard");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "str_split_at", reason = "recently added")]
|
||||
pub fn split_at(&self, mid: usize) -> (&str, &str) {
|
||||
core_str::StrExt::split_at(self, mid)
|
||||
}
|
||||
|
||||
/// An iterator over the codepoints of `self`.
|
||||
/// Divide one mutable string slice into two at an index.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_split_at", reason = "recently added")]
|
||||
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
|
||||
core_str::StrExt::split_at_mut(self, mid)
|
||||
}
|
||||
|
||||
/// An iterator over the code points of `self`.
|
||||
///
|
||||
/// In Unicode relationship between code points and characters is complex.
|
||||
/// A single character may be composed of multiple code points
|
||||
/// (e.g. diacritical marks added to a letter), and a single code point
|
||||
/// (e.g. Hangul syllable) may contain multiple characters.
|
||||
///
|
||||
/// For iteration over human-readable characters a grapheme cluster iterator
|
||||
/// may be more appropriate. See the [unicode-segmentation crate][1].
|
||||
///
|
||||
/// [1]: https://crates.io/crates/unicode-segmentation
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v: Vec<char> = "abc åäö".chars().collect();
|
||||
/// let v: Vec<char> = "ASCII żółć 🇨🇭 한".chars().collect();
|
||||
///
|
||||
/// assert_eq!(v, ['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
|
||||
/// assert_eq!(v, ['A', 'S', 'C', 'I', 'I', ' ',
|
||||
/// 'z', '\u{307}', 'o', '\u{301}', 'ł', 'c', '\u{301}', ' ',
|
||||
/// '\u{1f1e8}', '\u{1f1ed}', ' ', '한']);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn chars(&self) -> Chars {
|
||||
core_str::StrExt::chars(self)
|
||||
}
|
||||
|
||||
/// An iterator over the characters of `self` and their byte offsets.
|
||||
/// An iterator over the `char`s of `self` and their byte offsets.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v: Vec<(usize, char)> = "abc".char_indices().collect();
|
||||
/// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')];
|
||||
/// let v: Vec<(usize, char)> = "A🇨🇭".char_indices().collect();
|
||||
/// let b = vec![(0, 'A'), (1, '\u{1f1e8}'), (5, '\u{1f1ed}')];
|
||||
///
|
||||
/// assert_eq!(v, b);
|
||||
/// ```
|
||||
@ -855,7 +846,7 @@ impl str {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||
/// let some_words = " Mary had\ta\u{2009}little \n\t lamb";
|
||||
/// let v: Vec<&str> = some_words.split_whitespace().collect();
|
||||
///
|
||||
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||
@ -873,7 +864,7 @@ impl str {
|
||||
/// ```
|
||||
/// # #![feature(str_words)]
|
||||
/// # #![allow(deprecated)]
|
||||
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||
/// let some_words = " Mary had\ta\u{2009}little \n\t lamb";
|
||||
/// let v: Vec<&str> = some_words.words().collect();
|
||||
///
|
||||
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||
@ -1859,8 +1850,6 @@ impl str {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(str_casing)]
|
||||
///
|
||||
/// let s = "HELLO";
|
||||
/// assert_eq!(s.to_lowercase(), "hello");
|
||||
/// ```
|
||||
@ -1905,8 +1894,6 @@ impl str {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(str_casing)]
|
||||
///
|
||||
/// let s = "hello";
|
||||
/// assert_eq!(s.to_uppercase(), "HELLO");
|
||||
/// ```
|
||||
@ -1930,4 +1917,14 @@ impl str {
|
||||
pub fn escape_unicode(&self) -> String {
|
||||
self.chars().flat_map(|c| c.escape_unicode()).collect()
|
||||
}
|
||||
|
||||
/// Converts the `Box<str>` into a `String` without copying or allocating.
|
||||
#[unstable(feature = "box_str",
|
||||
reason = "recently added, matches RFC")]
|
||||
pub fn into_string(self: Box<str>) -> String {
|
||||
unsafe {
|
||||
let slice = mem::transmute::<Box<str>, Box<[u8]>>(self);
|
||||
String::from_utf8_unchecked(slice.into_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ use rustc_unicode::str::Utf16Item;
|
||||
use borrow::{Cow, IntoCow};
|
||||
use range::RangeArgument;
|
||||
use str::{self, FromStr, Utf8Error, Chars};
|
||||
use vec::{DerefVec, Vec, as_vec};
|
||||
use vec::Vec;
|
||||
use boxed::Box;
|
||||
|
||||
/// A growable string stored as a UTF-8 encoded buffer.
|
||||
#[derive(Clone, PartialOrd, Eq, Ord)]
|
||||
@ -317,9 +318,14 @@ impl String {
|
||||
|
||||
/// Creates a new `String` from a length, capacity, and pointer.
|
||||
///
|
||||
/// This is unsafe because:
|
||||
/// # Unsafety
|
||||
///
|
||||
/// * We call `Vec::from_raw_parts` to get a `Vec<u8>`;
|
||||
/// This is _very_ unsafe because:
|
||||
///
|
||||
/// * We call `Vec::from_raw_parts` to get a `Vec<u8>`. Therefore, this
|
||||
/// function inherits all of its unsafety, see [its
|
||||
/// documentation](../vec/struct.Vec.html#method.from_raw_parts)
|
||||
/// for the invariants it expects, they also apply to this function.
|
||||
/// * We assume that the `Vec` contains valid UTF-8.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -736,6 +742,16 @@ impl String {
|
||||
string: self_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the string into `Box<str>`.
|
||||
///
|
||||
/// Note that this will drop any excess capacity.
|
||||
#[unstable(feature = "box_str",
|
||||
reason = "recently added, matches RFC")]
|
||||
pub fn into_boxed_slice(self) -> Box<str> {
|
||||
let slice = self.vec.into_boxed_slice();
|
||||
unsafe { mem::transmute::<Box<[u8]>, Box<str>>(slice) }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUtf8Error {
|
||||
@ -963,6 +979,35 @@ impl ops::Index<ops::RangeFull> for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
|
||||
impl ops::IndexMut<ops::Range<usize>> for String {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
|
||||
&mut self[..][index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
|
||||
impl ops::IndexMut<ops::RangeTo<usize>> for String {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
|
||||
&mut self[..][index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
|
||||
impl ops::IndexMut<ops::RangeFrom<usize>> for String {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
|
||||
&mut self[..][index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
|
||||
impl ops::IndexMut<ops::RangeFull> for String {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
|
||||
unsafe { mem::transmute(&mut *self.vec) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Deref for String {
|
||||
type Target = str;
|
||||
@ -973,49 +1018,14 @@ impl ops::Deref for String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type providing a `&String` reference via `Deref`.
|
||||
#[unstable(feature = "collections")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
#[allow(deprecated)]
|
||||
pub struct DerefString<'a> {
|
||||
x: DerefVec<'a, u8>
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<'a> Deref for DerefString<'a> {
|
||||
type Target = String;
|
||||
|
||||
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
|
||||
impl ops::DerefMut for String {
|
||||
#[inline]
|
||||
fn deref<'b>(&'b self) -> &'b String {
|
||||
unsafe { mem::transmute(&*self.x) }
|
||||
fn deref_mut(&mut self) -> &mut str {
|
||||
unsafe { mem::transmute(&mut self.vec[..]) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a string slice to a wrapper type providing a `&String` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections)]
|
||||
/// use std::string::as_string;
|
||||
///
|
||||
/// // Let's pretend we have a function that requires `&String`
|
||||
/// fn string_consumer(s: &String) {
|
||||
/// assert_eq!(s, "foo");
|
||||
/// }
|
||||
///
|
||||
/// // Provide a `&String` from a `&str` without allocating
|
||||
/// string_consumer(&as_string("foo"));
|
||||
/// ```
|
||||
#[unstable(feature = "collections")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
#[allow(deprecated)]
|
||||
pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {
|
||||
DerefString { x: as_vec(x.as_bytes()) }
|
||||
}
|
||||
|
||||
/// Error returned from `String::from`
|
||||
#[unstable(feature = "str_parse_error", reason = "may want to be replaced with \
|
||||
Void if it ever exists")]
|
||||
|
@ -59,32 +59,25 @@
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use alloc::raw_vec::RawVec;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::heap::{EMPTY, allocate, reallocate, deallocate};
|
||||
use core::cmp::max;
|
||||
use alloc::heap::EMPTY;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::intrinsics::{arith_offset, assume};
|
||||
use core::iter::{repeat, FromIterator};
|
||||
use core::intrinsics::{arith_offset, assume, drop_in_place};
|
||||
use core::iter::FromIterator;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ops::{Index, IndexMut, Deref};
|
||||
use core::ops;
|
||||
use core::ptr;
|
||||
use core::ptr::Unique;
|
||||
use core::slice;
|
||||
use core::isize;
|
||||
use core::usize;
|
||||
|
||||
use borrow::{Cow, IntoCow};
|
||||
|
||||
use super::range::RangeArgument;
|
||||
|
||||
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
|
||||
const MAX_MEMORY_SIZE: usize = isize::MAX as usize;
|
||||
|
||||
/// A growable list type, written `Vec<T>` but pronounced 'vector.'
|
||||
///
|
||||
/// # Examples
|
||||
@ -152,14 +145,10 @@ const MAX_MEMORY_SIZE: usize = isize::MAX as usize;
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Vec<T> {
|
||||
ptr: Unique<T>,
|
||||
buf: RawVec<T>,
|
||||
len: usize,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Vec<T> { }
|
||||
unsafe impl<T: Sync> Sync for Vec<T> { }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Inherent methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -177,11 +166,7 @@ impl<T> Vec<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new() -> Vec<T> {
|
||||
// We want ptr to never be NULL so instead we set it to some arbitrary
|
||||
// non-null value which is fine since we never call deallocate on the ptr
|
||||
// if cap is 0. The reason for this is because the pointer of a slice
|
||||
// being NULL would break the null pointer optimization for enums.
|
||||
unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, 0) }
|
||||
Vec { buf: RawVec::new(), len: 0 }
|
||||
}
|
||||
|
||||
/// Constructs a new, empty `Vec<T>` with the specified capacity.
|
||||
@ -212,22 +197,23 @@ impl<T> Vec<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_capacity(capacity: usize) -> Vec<T> {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, usize::MAX) }
|
||||
} else if capacity == 0 {
|
||||
Vec::new()
|
||||
} else {
|
||||
let size = capacity.checked_mul(mem::size_of::<T>())
|
||||
.expect("capacity overflow");
|
||||
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
unsafe { Vec::from_raw_parts(ptr as *mut T, 0, capacity) }
|
||||
}
|
||||
Vec { buf: RawVec::with_capacity(capacity), len: 0 }
|
||||
}
|
||||
|
||||
/// Creates a `Vec<T>` directly from the raw components of another vector.
|
||||
///
|
||||
/// This is highly unsafe, due to the number of invariants that aren't checked.
|
||||
/// # Unsafety
|
||||
///
|
||||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * `ptr` needs to have been previously allocated via `String`/`Vec<T>`
|
||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
||||
/// * `length` needs to be the length that less than or equal to `capacity`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -263,9 +249,8 @@ impl<T> Vec<T> {
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize,
|
||||
capacity: usize) -> Vec<T> {
|
||||
Vec {
|
||||
ptr: Unique::new(ptr),
|
||||
buf: RawVec::from_raw_parts(ptr, capacity),
|
||||
len: length,
|
||||
cap: capacity,
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,7 +284,7 @@ impl<T> Vec<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.cap
|
||||
self.buf.cap()
|
||||
}
|
||||
|
||||
/// Reserves capacity for at least `additional` more elements to be inserted
|
||||
@ -319,17 +304,7 @@ impl<T> Vec<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
if self.cap - self.len < additional {
|
||||
const ERR_MSG: &'static str = "Vec::reserve: `isize` overflow";
|
||||
|
||||
let new_min_cap = self.len.checked_add(additional).expect(ERR_MSG);
|
||||
if new_min_cap > MAX_MEMORY_SIZE { panic!(ERR_MSG) }
|
||||
self.grow_capacity(match new_min_cap.checked_next_power_of_two() {
|
||||
Some(x) if x > MAX_MEMORY_SIZE => MAX_MEMORY_SIZE,
|
||||
None => MAX_MEMORY_SIZE,
|
||||
Some(x) => x,
|
||||
});
|
||||
}
|
||||
self.buf.reserve(self.len, additional);
|
||||
}
|
||||
|
||||
/// Reserves the minimum capacity for exactly `additional` more elements to
|
||||
@ -353,12 +328,7 @@ impl<T> Vec<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn reserve_exact(&mut self, additional: usize) {
|
||||
if self.cap - self.len < additional {
|
||||
match self.len.checked_add(additional) {
|
||||
None => panic!("Vec::reserve: `usize` overflow"),
|
||||
Some(new_cap) => self.grow_capacity(new_cap)
|
||||
}
|
||||
}
|
||||
self.buf.reserve_exact(self.len, additional);
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of the vector as much as possible.
|
||||
@ -377,28 +347,7 @@ impl<T> Vec<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
if mem::size_of::<T>() == 0 { return }
|
||||
|
||||
if self.len == 0 {
|
||||
if self.cap != 0 {
|
||||
unsafe {
|
||||
dealloc(*self.ptr, self.cap)
|
||||
}
|
||||
self.cap = 0;
|
||||
}
|
||||
} else if self.cap != self.len {
|
||||
unsafe {
|
||||
// Overflow check is unnecessary as the vector is already at
|
||||
// least this large.
|
||||
let ptr = reallocate(*self.ptr as *mut u8,
|
||||
self.cap * mem::size_of::<T>(),
|
||||
self.len * mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>()) as *mut T;
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
self.ptr = Unique::new(ptr);
|
||||
}
|
||||
self.cap = self.len;
|
||||
}
|
||||
self.buf.shrink_to_fit(self.len);
|
||||
}
|
||||
|
||||
/// Converts the vector into Box<[T]>.
|
||||
@ -408,11 +357,11 @@ impl<T> Vec<T> {
|
||||
/// `shrink_to_fit()`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_boxed_slice(mut self) -> Box<[T]> {
|
||||
self.shrink_to_fit();
|
||||
unsafe {
|
||||
let xs: Box<[T]> = Box::from_raw(&mut *self);
|
||||
self.shrink_to_fit();
|
||||
let buf = ptr::read(&self.buf);
|
||||
mem::forget(self);
|
||||
xs
|
||||
buf.into_box()
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,8 +478,9 @@ impl<T> Vec<T> {
|
||||
pub fn insert(&mut self, index: usize, element: T) {
|
||||
let len = self.len();
|
||||
assert!(index <= len);
|
||||
|
||||
// space for the new element
|
||||
self.reserve(1);
|
||||
if len == self.buf.cap() { self.buf.double(); }
|
||||
|
||||
unsafe { // infallible
|
||||
// The spot to put the new value
|
||||
@ -538,10 +488,10 @@ impl<T> Vec<T> {
|
||||
let p = self.as_mut_ptr().offset(index as isize);
|
||||
// Shift everything over to make space. (Duplicating the
|
||||
// `index`th element into two consecutive places.)
|
||||
ptr::copy(&*p, p.offset(1), len - index);
|
||||
ptr::copy(p, p.offset(1), len - index);
|
||||
// Write it in, overwriting the first copy of the `index`th
|
||||
// element.
|
||||
ptr::write(&mut *p, element);
|
||||
ptr::write(p, element);
|
||||
}
|
||||
self.set_len(len + 1);
|
||||
}
|
||||
@ -575,7 +525,7 @@ impl<T> Vec<T> {
|
||||
ret = ptr::read(ptr);
|
||||
|
||||
// Shift everything down to fill in that spot.
|
||||
ptr::copy(&*ptr.offset(1), ptr, len - index - 1);
|
||||
ptr::copy(ptr.offset(1), ptr, len - index - 1);
|
||||
}
|
||||
self.set_len(len - 1);
|
||||
ret
|
||||
@ -631,38 +581,12 @@ impl<T> Vec<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push(&mut self, value: T) {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn resize<T>(vec: &mut Vec<T>) {
|
||||
let old_size = vec.cap * mem::size_of::<T>();
|
||||
if old_size >= MAX_MEMORY_SIZE { panic!("capacity overflow") }
|
||||
let mut size = max(old_size, 2 * mem::size_of::<T>()) * 2;
|
||||
if old_size > size || size > MAX_MEMORY_SIZE {
|
||||
size = MAX_MEMORY_SIZE;
|
||||
}
|
||||
unsafe {
|
||||
let ptr = alloc_or_realloc(*vec.ptr, old_size, size);
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
vec.ptr = Unique::new(ptr);
|
||||
}
|
||||
vec.cap = max(vec.cap, 2) * 2;
|
||||
}
|
||||
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// zero-size types consume no memory, so we can't rely on the
|
||||
// address space running out
|
||||
self.len = self.len.checked_add(1).expect("length overflow");
|
||||
mem::forget(value);
|
||||
return
|
||||
}
|
||||
|
||||
if self.len == self.cap {
|
||||
resize(self);
|
||||
}
|
||||
|
||||
// This will panic or abort if we would allocate > isize::MAX bytes
|
||||
// or if the length increment would overflow for zero-sized types.
|
||||
if self.len == self.buf.cap() { self.buf.double(); }
|
||||
unsafe {
|
||||
let end = (*self.ptr).offset(self.len as isize);
|
||||
ptr::write(&mut *end, value);
|
||||
let end = self.as_mut_ptr().offset(self.len as isize);
|
||||
ptr::write(end, value);
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
@ -709,13 +633,6 @@ impl<T> Vec<T> {
|
||||
#[unstable(feature = "append",
|
||||
reason = "new API, waiting for dust to settle")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// zero-size types consume no memory, so we can't rely on the
|
||||
// address space running out
|
||||
self.len = self.len.checked_add(other.len()).expect("length overflow");
|
||||
unsafe { other.set_len(0) }
|
||||
return;
|
||||
}
|
||||
self.reserve(other.len());
|
||||
let len = self.len();
|
||||
unsafe {
|
||||
@ -866,9 +783,9 @@ impl<T> Vec<T> {
|
||||
// FIXME: Assert statically that the types `T` and `U` have the
|
||||
// same minimal alignment in case they are not zero-sized.
|
||||
|
||||
// These asserts are necessary because the `min_align_of` of the
|
||||
// These asserts are necessary because the `align_of` of the
|
||||
// types are passed to the allocator by `Vec`.
|
||||
assert!(mem::min_align_of::<T>() == mem::min_align_of::<U>());
|
||||
assert!(mem::align_of::<T>() == mem::align_of::<U>());
|
||||
|
||||
// This `as isize` cast is safe, because the size of the elements of the
|
||||
// vector is not 0, and:
|
||||
@ -1099,12 +1016,35 @@ impl<T: Clone> Vec<T> {
|
||||
let len = self.len();
|
||||
|
||||
if new_len > len {
|
||||
self.extend(repeat(value).take(new_len - len));
|
||||
self.extend_with_element(new_len - len, value);
|
||||
} else {
|
||||
self.truncate(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend the vector by `n` additional clones of `value`.
|
||||
fn extend_with_element(&mut self, n: usize, value: T) {
|
||||
self.reserve(n);
|
||||
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let mut ptr = self.as_mut_ptr().offset(len as isize);
|
||||
// Write all elements except the last one
|
||||
for i in 1..n {
|
||||
ptr::write(ptr, value.clone());
|
||||
ptr = ptr.offset(1);
|
||||
// Increment the length in every step in case clone() panics
|
||||
self.set_len(len + i);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, value);
|
||||
self.set_len(len + n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends all elements in a slice to the `Vec`.
|
||||
///
|
||||
/// Iterates over the slice `other`, clones each element, and then appends
|
||||
@ -1244,68 +1184,12 @@ impl<T: PartialEq> Vec<T> {
|
||||
// Internal methods and functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T> Vec<T> {
|
||||
/// Reserves capacity for exactly `capacity` elements in the given vector.
|
||||
///
|
||||
/// If the capacity for `self` is already equal to or greater than the
|
||||
/// requested capacity, then no action is taken.
|
||||
fn grow_capacity(&mut self, capacity: usize) {
|
||||
if mem::size_of::<T>() == 0 { return }
|
||||
|
||||
if capacity > self.cap {
|
||||
let size = capacity.checked_mul(mem::size_of::<T>())
|
||||
.expect("capacity overflow");
|
||||
unsafe {
|
||||
let ptr = alloc_or_realloc(*self.ptr, self.cap * mem::size_of::<T>(), size);
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
self.ptr = Unique::new(ptr);
|
||||
}
|
||||
self.cap = capacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: #13996: need a way to mark the return value as `noalias`
|
||||
#[inline(never)]
|
||||
unsafe fn alloc_or_realloc<T>(ptr: *mut T, old_size: usize, size: usize) -> *mut T {
|
||||
if old_size == 0 {
|
||||
allocate(size, mem::min_align_of::<T>()) as *mut T
|
||||
} else {
|
||||
reallocate(ptr as *mut u8, old_size, size, mem::min_align_of::<T>()) as *mut T
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc<T>(ptr: *mut T, len: usize) {
|
||||
if mem::size_of::<T>() != 0 {
|
||||
deallocate(ptr as *mut u8,
|
||||
len * mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
|
||||
unsafe {
|
||||
let mut v = Vec::with_capacity(n);
|
||||
let mut ptr = v.as_mut_ptr();
|
||||
|
||||
// Write all elements except the last one
|
||||
for i in 1..n {
|
||||
ptr::write(ptr, Clone::clone(&elem));
|
||||
ptr = ptr.offset(1);
|
||||
v.set_len(i); // Increment the length in every step in case Clone::clone() panics
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, elem);
|
||||
v.set_len(n);
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
let mut v = Vec::with_capacity(n);
|
||||
v.extend_with_element(n, elem);
|
||||
v
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1449,7 +1333,7 @@ impl<T> ops::Deref for Vec<T> {
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
unsafe {
|
||||
let p = *self.ptr;
|
||||
let p = self.buf.ptr();
|
||||
assume(p != 0 as *mut T);
|
||||
slice::from_raw_parts(p, self.len)
|
||||
}
|
||||
@ -1460,7 +1344,7 @@ impl<T> ops::Deref for Vec<T> {
|
||||
impl<T> ops::DerefMut for Vec<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
unsafe {
|
||||
let ptr = *self.ptr;
|
||||
let ptr = self.buf.ptr();
|
||||
assume(!ptr.is_null());
|
||||
slice::from_raw_parts_mut(ptr, self.len)
|
||||
}
|
||||
@ -1482,7 +1366,7 @@ impl<T> FromIterator<T> for Vec<T> {
|
||||
None => return Vec::new(),
|
||||
Some(element) => {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
let mut vector = Vec::with_capacity(1 + lower);
|
||||
let mut vector = Vec::with_capacity(lower.saturating_add(1));
|
||||
unsafe {
|
||||
ptr::write(vector.get_unchecked_mut(0), element);
|
||||
vector.set_len(1);
|
||||
@ -1514,19 +1398,19 @@ impl<T> IntoIterator for Vec<T> {
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
fn into_iter(mut self) -> IntoIter<T> {
|
||||
unsafe {
|
||||
let ptr = *self.ptr;
|
||||
let ptr = self.as_mut_ptr();
|
||||
assume(!ptr.is_null());
|
||||
let cap = self.cap;
|
||||
let begin = ptr as *const T;
|
||||
let end = if mem::size_of::<T>() == 0 {
|
||||
arith_offset(ptr as *const i8, self.len() as isize) as *const T
|
||||
} else {
|
||||
ptr.offset(self.len() as isize) as *const T
|
||||
};
|
||||
let buf = ptr::read(&self.buf);
|
||||
mem::forget(self);
|
||||
IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end }
|
||||
IntoIter { buf: buf, ptr: begin, end: end }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1570,10 +1454,11 @@ impl<T> Vec<T> {
|
||||
let len = self.len();
|
||||
if len == self.capacity() {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
self.reserve(lower + 1);
|
||||
self.reserve(lower.saturating_add(1));
|
||||
}
|
||||
unsafe {
|
||||
ptr::write(self.get_unchecked_mut(len), element);
|
||||
// NB can't overflow since we would have had to alloc the address space
|
||||
self.set_len(len + 1);
|
||||
}
|
||||
}
|
||||
@ -1637,16 +1522,16 @@ impl<T: Ord> Ord for Vec<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Vec<T> {
|
||||
fn drop(&mut self) {
|
||||
// This is (and should always remain) a no-op if the fields are
|
||||
// zeroed (when moving out, because of #[unsafe_no_drop_flag]).
|
||||
if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
|
||||
unsafe {
|
||||
for x in self.iter() {
|
||||
ptr::read(x);
|
||||
}
|
||||
dealloc(*self.ptr, self.cap)
|
||||
// NOTE: this is currently abusing the fact that ZSTs can't impl Drop.
|
||||
// Or rather, that impl'ing Drop makes them not zero-sized. This is
|
||||
// OK because exactly when this stops being a valid assumption, we
|
||||
// don't need unsafe_no_drop_flag shenanigans anymore.
|
||||
if self.buf.unsafe_no_drop_flag_needs_drop() {
|
||||
for x in self.iter_mut() {
|
||||
unsafe { drop_in_place(x); }
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation
|
||||
}
|
||||
}
|
||||
|
||||
@ -1730,8 +1615,7 @@ impl<'a, T> IntoCow<'a, [T]> for &'a [T] where T: Clone {
|
||||
/// An iterator that moves out of a vector.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IntoIter<T> {
|
||||
allocation: *mut T, // the block of memory allocated for the vector
|
||||
cap: usize, // the capacity of the vector
|
||||
buf: RawVec<T>,
|
||||
ptr: *const T,
|
||||
end: *const T
|
||||
}
|
||||
@ -1746,9 +1630,9 @@ impl<T> IntoIter<T> {
|
||||
pub fn into_inner(mut self) -> Vec<T> {
|
||||
unsafe {
|
||||
for _x in self.by_ref() { }
|
||||
let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self;
|
||||
let buf = ptr::read(&self.buf);
|
||||
mem::forget(self);
|
||||
Vec::from_raw_parts(allocation, 0, cap)
|
||||
Vec { buf: buf, len: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1826,12 +1710,9 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
|
||||
impl<T> Drop for IntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
// destroy the remaining elements
|
||||
if self.cap != 0 {
|
||||
for _x in self.by_ref() {}
|
||||
unsafe {
|
||||
dealloc(self.allocation, self.cap);
|
||||
}
|
||||
}
|
||||
for _x in self.by_ref() {}
|
||||
|
||||
// RawVec handles deallocation
|
||||
}
|
||||
}
|
||||
|
||||
@ -1905,73 +1786,6 @@ impl<'a, T> Drop for Drain<'a, T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Conversion from &[T] to &Vec<T>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Wrapper type providing a `&Vec<T>` reference via `Deref`.
|
||||
#[unstable(feature = "collections")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
pub struct DerefVec<'a, T:'a> {
|
||||
x: Vec<T>,
|
||||
l: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
#[allow(deprecated)]
|
||||
impl<'a, T> Deref for DerefVec<'a, T> {
|
||||
type Target = Vec<T>;
|
||||
|
||||
fn deref<'b>(&'b self) -> &'b Vec<T> {
|
||||
&self.x
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent the inner `Vec<T>` from attempting to deallocate memory.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
#[allow(deprecated)]
|
||||
impl<'a, T> Drop for DerefVec<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.x.len = 0;
|
||||
self.x.cap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a slice to a wrapper type providing a `&Vec<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections)]
|
||||
/// use std::vec::as_vec;
|
||||
///
|
||||
/// // Let's pretend we have a function that requires `&Vec<i32>`
|
||||
/// fn vec_consumer(s: &Vec<i32>) {
|
||||
/// assert_eq!(s, &[1, 2, 3]);
|
||||
/// }
|
||||
///
|
||||
/// // Provide a `&Vec<i32>` from a `&[i32]` without allocating
|
||||
/// let values = [1, 2, 3];
|
||||
/// vec_consumer(&as_vec(&values));
|
||||
/// ```
|
||||
#[unstable(feature = "collections")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "replaced with deref coercions or Borrow")]
|
||||
#[allow(deprecated)]
|
||||
pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
|
||||
unsafe {
|
||||
DerefVec {
|
||||
x: Vec::from_raw_parts(x.as_ptr() as *mut T, x.len(), x.len()),
|
||||
l: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Partial vec, used for map_in_place
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -23,33 +23,35 @@ use core::prelude::*;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::iter::{self, repeat, FromIterator, RandomAccessIterator};
|
||||
use core::mem;
|
||||
use core::ops::{Index, IndexMut};
|
||||
use core::ptr::{self, Unique};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::cmp;
|
||||
|
||||
use alloc::heap;
|
||||
use alloc::raw_vec::RawVec;
|
||||
|
||||
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
|
||||
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
|
||||
|
||||
/// `VecDeque` is a growable ring buffer, which can be used as a
|
||||
/// double-ended queue efficiently.
|
||||
///
|
||||
/// The "default" usage of this type as a queue is to use `push_back` to add to the queue, and
|
||||
/// `pop_front` to remove from the queue. `extend` and `append` push onto the back in this manner,
|
||||
/// and iterating over `VecDeque` goes front to back.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct VecDeque<T> {
|
||||
// tail and head are pointers into the buffer. Tail always points
|
||||
// to the first element that could be read, Head always points
|
||||
// to where data should be written.
|
||||
// If tail == head the buffer is empty. The length of the ringbuf
|
||||
// If tail == head the buffer is empty. The length of the ringbuffer
|
||||
// is defined as the distance between the two.
|
||||
|
||||
tail: usize,
|
||||
head: usize,
|
||||
cap: usize,
|
||||
ptr: Unique<T>,
|
||||
buf: RawVec<T>,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -63,13 +65,7 @@ impl<T: Clone> Clone for VecDeque<T> {
|
||||
impl<T> Drop for VecDeque<T> {
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
unsafe {
|
||||
if mem::size_of::<T>() != 0 {
|
||||
heap::deallocate(*self.ptr as *mut u8,
|
||||
self.cap * mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>())
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,78 +76,127 @@ impl<T> Default for VecDeque<T> {
|
||||
}
|
||||
|
||||
impl<T> VecDeque<T> {
|
||||
/// Marginally more convenient
|
||||
#[inline]
|
||||
fn ptr(&self) -> *mut T {
|
||||
self.buf.ptr()
|
||||
}
|
||||
|
||||
/// Marginally more convenient
|
||||
#[inline]
|
||||
fn cap(&self) -> usize {
|
||||
self.buf.cap()
|
||||
}
|
||||
|
||||
/// Turn ptr into a slice
|
||||
#[inline]
|
||||
unsafe fn buffer_as_slice(&self) -> &[T] {
|
||||
slice::from_raw_parts(*self.ptr, self.cap)
|
||||
slice::from_raw_parts(self.ptr(), self.cap())
|
||||
}
|
||||
|
||||
/// Turn ptr into a mut slice
|
||||
#[inline]
|
||||
unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] {
|
||||
slice::from_raw_parts_mut(*self.ptr, self.cap)
|
||||
slice::from_raw_parts_mut(self.ptr(), self.cap())
|
||||
}
|
||||
|
||||
/// Moves an element out of the buffer
|
||||
#[inline]
|
||||
unsafe fn buffer_read(&mut self, off: usize) -> T {
|
||||
ptr::read(self.ptr.offset(off as isize))
|
||||
ptr::read(self.ptr().offset(off as isize))
|
||||
}
|
||||
|
||||
/// Writes an element into the buffer, moving it.
|
||||
#[inline]
|
||||
unsafe fn buffer_write(&mut self, off: usize, t: T) {
|
||||
ptr::write(self.ptr.offset(off as isize), t);
|
||||
unsafe fn buffer_write(&mut self, off: usize, value: T) {
|
||||
ptr::write(self.ptr().offset(off as isize), value);
|
||||
}
|
||||
|
||||
/// Returns true iff the buffer is at capacity
|
||||
/// Returns true if and only if the buffer is at capacity
|
||||
#[inline]
|
||||
fn is_full(&self) -> bool { self.cap - self.len() == 1 }
|
||||
fn is_full(&self) -> bool { self.cap() - self.len() == 1 }
|
||||
|
||||
/// Returns the index in the underlying buffer for a given logical element
|
||||
/// index.
|
||||
#[inline]
|
||||
fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap) }
|
||||
fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap()) }
|
||||
|
||||
/// Returns the index in the underlying buffer for a given logical element
|
||||
/// index + addend.
|
||||
#[inline]
|
||||
fn wrap_add(&self, idx: usize, addend: usize) -> usize {
|
||||
wrap_index(idx.wrapping_add(addend), self.cap)
|
||||
wrap_index(idx.wrapping_add(addend), self.cap())
|
||||
}
|
||||
|
||||
/// Returns the index in the underlying buffer for a given logical element
|
||||
/// index - subtrahend.
|
||||
#[inline]
|
||||
fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize {
|
||||
wrap_index(idx.wrapping_sub(subtrahend), self.cap)
|
||||
wrap_index(idx.wrapping_sub(subtrahend), self.cap())
|
||||
}
|
||||
|
||||
/// Copies a contiguous block of memory len long from src to dst
|
||||
#[inline]
|
||||
unsafe fn copy(&self, dst: usize, src: usize, len: usize) {
|
||||
debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap);
|
||||
debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap);
|
||||
debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap());
|
||||
debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap());
|
||||
ptr::copy(
|
||||
self.ptr.offset(src as isize),
|
||||
self.ptr.offset(dst as isize),
|
||||
self.ptr().offset(src as isize),
|
||||
self.ptr().offset(dst as isize),
|
||||
len);
|
||||
}
|
||||
|
||||
/// Copies a contiguous block of memory len long from src to dst
|
||||
#[inline]
|
||||
unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) {
|
||||
debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap);
|
||||
debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap);
|
||||
debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap());
|
||||
debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len,
|
||||
self.cap());
|
||||
ptr::copy_nonoverlapping(
|
||||
self.ptr.offset(src as isize),
|
||||
self.ptr.offset(dst as isize),
|
||||
self.ptr().offset(src as isize),
|
||||
self.ptr().offset(dst as isize),
|
||||
len);
|
||||
}
|
||||
|
||||
/// Frobs the head and tail sections around to handle the fact that we
|
||||
/// just reallocated. Unsafe because it trusts old_cap.
|
||||
#[inline]
|
||||
unsafe fn handle_cap_increase(&mut self, old_cap: usize) {
|
||||
let new_cap = self.cap();
|
||||
|
||||
// Move the shortest contiguous section of the ring buffer
|
||||
// T H
|
||||
// [o o o o o o o . ]
|
||||
// T H
|
||||
// A [o o o o o o o . . . . . . . . . ]
|
||||
// H T
|
||||
// [o o . o o o o o ]
|
||||
// T H
|
||||
// B [. . . o o o o o o o . . . . . . ]
|
||||
// H T
|
||||
// [o o o o o . o o ]
|
||||
// H T
|
||||
// C [o o o o o . . . . . . . . . o o ]
|
||||
|
||||
if self.tail <= self.head { // A
|
||||
// Nop
|
||||
} else if self.head < old_cap - self.tail { // B
|
||||
self.copy_nonoverlapping(old_cap, 0, self.head);
|
||||
self.head += old_cap;
|
||||
debug_assert!(self.head > self.tail);
|
||||
} else { // C
|
||||
let new_tail = new_cap - (old_cap - self.tail);
|
||||
self.copy_nonoverlapping(new_tail, self.tail, old_cap - self.tail);
|
||||
self.tail = new_tail;
|
||||
debug_assert!(self.head < self.tail);
|
||||
}
|
||||
debug_assert!(self.head < self.cap());
|
||||
debug_assert!(self.tail < self.cap());
|
||||
debug_assert!(self.cap().count_ones() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VecDeque<T> {
|
||||
@ -167,24 +212,11 @@ impl<T> VecDeque<T> {
|
||||
// +1 since the ringbuffer always leaves one space empty
|
||||
let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
|
||||
assert!(cap > n, "capacity overflow");
|
||||
let size = cap.checked_mul(mem::size_of::<T>())
|
||||
.expect("capacity overflow");
|
||||
|
||||
let ptr = unsafe {
|
||||
if mem::size_of::<T>() != 0 {
|
||||
let ptr = heap::allocate(size, mem::min_align_of::<T>()) as *mut T;;
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
Unique::new(ptr)
|
||||
} else {
|
||||
Unique::new(heap::EMPTY as *mut T)
|
||||
}
|
||||
};
|
||||
|
||||
VecDeque {
|
||||
tail: 0,
|
||||
head: 0,
|
||||
cap: cap,
|
||||
ptr: ptr,
|
||||
buf: RawVec::with_capacity(cap),
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,10 +234,10 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(buf.get(1).unwrap(), &4);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self, i: usize) -> Option<&T> {
|
||||
if i < self.len() {
|
||||
let idx = self.wrap_add(self.tail, i);
|
||||
unsafe { Some(&*self.ptr.offset(idx as isize)) }
|
||||
pub fn get(&self, index: usize) -> Option<&T> {
|
||||
if index < self.len() {
|
||||
let idx = self.wrap_add(self.tail, index);
|
||||
unsafe { Some(&*self.ptr().offset(idx as isize)) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -229,10 +261,10 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(buf[1], 7);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
|
||||
if i < self.len() {
|
||||
let idx = self.wrap_add(self.tail, i);
|
||||
unsafe { Some(&mut *self.ptr.offset(idx as isize)) }
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
||||
if index < self.len() {
|
||||
let idx = self.wrap_add(self.tail, index);
|
||||
unsafe { Some(&mut *self.ptr().offset(idx as isize)) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -264,7 +296,7 @@ impl<T> VecDeque<T> {
|
||||
let ri = self.wrap_add(self.tail, i);
|
||||
let rj = self.wrap_add(self.tail, j);
|
||||
unsafe {
|
||||
ptr::swap(self.ptr.offset(ri as isize), self.ptr.offset(rj as isize))
|
||||
ptr::swap(self.ptr().offset(ri as isize), self.ptr().offset(rj as isize))
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +313,7 @@ impl<T> VecDeque<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn capacity(&self) -> usize { self.cap - 1 }
|
||||
pub fn capacity(&self) -> usize { self.cap() - 1 }
|
||||
|
||||
/// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the
|
||||
/// given `VecDeque`. Does nothing if the capacity is already sufficient.
|
||||
@ -309,7 +341,7 @@ impl<T> VecDeque<T> {
|
||||
}
|
||||
|
||||
/// Reserves capacity for at least `additional` more elements to be inserted in the given
|
||||
/// `Ringbuf`. The collection may reserve more space to avoid frequent reallocations.
|
||||
/// `VecDeque`. The collection may reserve more space to avoid frequent reallocations.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -326,69 +358,23 @@ impl<T> VecDeque<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
let new_len = self.len() + additional;
|
||||
assert!(new_len + 1 > self.len(), "capacity overflow");
|
||||
if new_len > self.capacity() {
|
||||
let count = (new_len + 1).next_power_of_two();
|
||||
assert!(count >= new_len + 1);
|
||||
let old_cap = self.cap();
|
||||
let used_cap = self.len() + 1;
|
||||
let new_cap = used_cap
|
||||
.checked_add(additional)
|
||||
.and_then(|needed_cap| needed_cap.checked_next_power_of_two())
|
||||
.expect("capacity overflow");
|
||||
|
||||
if mem::size_of::<T>() != 0 {
|
||||
let old = self.cap * mem::size_of::<T>();
|
||||
let new = count.checked_mul(mem::size_of::<T>())
|
||||
.expect("capacity overflow");
|
||||
unsafe {
|
||||
let ptr = heap::reallocate(*self.ptr as *mut u8,
|
||||
old,
|
||||
new,
|
||||
mem::min_align_of::<T>()) as *mut T;
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
self.ptr = Unique::new(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the shortest contiguous section of the ring buffer
|
||||
// T H
|
||||
// [o o o o o o o . ]
|
||||
// T H
|
||||
// A [o o o o o o o . . . . . . . . . ]
|
||||
// H T
|
||||
// [o o . o o o o o ]
|
||||
// T H
|
||||
// B [. . . o o o o o o o . . . . . . ]
|
||||
// H T
|
||||
// [o o o o o . o o ]
|
||||
// H T
|
||||
// C [o o o o o . . . . . . . . . o o ]
|
||||
|
||||
let oldcap = self.cap;
|
||||
self.cap = count;
|
||||
|
||||
if self.tail <= self.head { // A
|
||||
// Nop
|
||||
} else if self.head < oldcap - self.tail { // B
|
||||
unsafe {
|
||||
self.copy_nonoverlapping(oldcap, 0, self.head);
|
||||
}
|
||||
self.head += oldcap;
|
||||
debug_assert!(self.head > self.tail);
|
||||
} else { // C
|
||||
let new_tail = count - (oldcap - self.tail);
|
||||
unsafe {
|
||||
self.copy_nonoverlapping(new_tail, self.tail, oldcap - self.tail);
|
||||
}
|
||||
self.tail = new_tail;
|
||||
debug_assert!(self.head < self.tail);
|
||||
}
|
||||
debug_assert!(self.head < self.cap);
|
||||
debug_assert!(self.tail < self.cap);
|
||||
debug_assert!(self.cap.count_ones() == 1);
|
||||
if new_cap > self.capacity() {
|
||||
self.buf.reserve_exact(used_cap, new_cap - used_cap);
|
||||
unsafe { self.handle_cap_increase(old_cap); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of the ringbuf as much as possible.
|
||||
/// Shrinks the capacity of the `VecDeque` as much as possible.
|
||||
///
|
||||
/// It will drop down as close as possible to the length but the allocator may still inform the
|
||||
/// ringbuf that there is space for a few more elements.
|
||||
/// `VecDeque` that there is space for a few more elements.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -404,9 +390,9 @@ impl<T> VecDeque<T> {
|
||||
/// ```
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
// +1 since the ringbuffer always leaves one space empty
|
||||
// len + 1 can't overflow for an existing, well-formed ringbuf.
|
||||
// len + 1 can't overflow for an existing, well-formed ringbuffer.
|
||||
let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
|
||||
if target_cap < self.cap {
|
||||
if target_cap < self.cap() {
|
||||
// There are three cases of interest:
|
||||
// All elements are out of desired bounds
|
||||
// Elements are contiguous, and head is out of desired bounds
|
||||
@ -444,7 +430,7 @@ impl<T> VecDeque<T> {
|
||||
// H T
|
||||
// [o o o o o . o o ]
|
||||
debug_assert!(self.wrap_sub(self.head, 1) < target_cap);
|
||||
let len = self.cap - self.tail;
|
||||
let len = self.cap() - self.tail;
|
||||
let new_tail = target_cap - len;
|
||||
unsafe {
|
||||
self.copy_nonoverlapping(new_tail, self.tail, len);
|
||||
@ -453,28 +439,17 @@ impl<T> VecDeque<T> {
|
||||
debug_assert!(self.head < self.tail);
|
||||
}
|
||||
|
||||
if mem::size_of::<T>() != 0 {
|
||||
let old = self.cap * mem::size_of::<T>();
|
||||
let new_size = target_cap * mem::size_of::<T>();
|
||||
unsafe {
|
||||
let ptr = heap::reallocate(*self.ptr as *mut u8,
|
||||
old,
|
||||
new_size,
|
||||
mem::min_align_of::<T>()) as *mut T;
|
||||
if ptr.is_null() { ::alloc::oom() }
|
||||
self.ptr = Unique::new(ptr);
|
||||
}
|
||||
}
|
||||
self.cap = target_cap;
|
||||
debug_assert!(self.head < self.cap);
|
||||
debug_assert!(self.tail < self.cap);
|
||||
debug_assert!(self.cap.count_ones() == 1);
|
||||
self.buf.shrink_to_fit(target_cap);
|
||||
|
||||
debug_assert!(self.head < self.cap());
|
||||
debug_assert!(self.tail < self.cap());
|
||||
debug_assert!(self.cap().count_ones() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shortens a ringbuf, dropping excess elements from the back.
|
||||
/// Shortens a `VecDeque`, dropping excess elements from the back.
|
||||
///
|
||||
/// If `len` is greater than the ringbuf's current length, this has no
|
||||
/// If `len` is greater than the `VecDeque`'s current length, this has no
|
||||
/// effect.
|
||||
///
|
||||
/// # Examples
|
||||
@ -606,7 +581,7 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(v.len(), 1);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn len(&self) -> usize { count(self.tail, self.head, self.cap) }
|
||||
pub fn len(&self) -> usize { count(self.tail, self.head, self.cap()) }
|
||||
|
||||
/// Returns true if the buffer contains no elements
|
||||
///
|
||||
@ -793,15 +768,17 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(d.front(), Some(&2));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_front(&mut self, t: T) {
|
||||
pub fn push_front(&mut self, value: T) {
|
||||
if self.is_full() {
|
||||
self.reserve(1);
|
||||
let old_cap = self.cap();
|
||||
self.buf.double();
|
||||
unsafe { self.handle_cap_increase(old_cap); }
|
||||
debug_assert!(!self.is_full());
|
||||
}
|
||||
|
||||
self.tail = self.wrap_sub(self.tail, 1);
|
||||
let tail = self.tail;
|
||||
unsafe { self.buffer_write(tail, t); }
|
||||
unsafe { self.buffer_write(tail, value); }
|
||||
}
|
||||
|
||||
/// Appends an element to the back of a buffer
|
||||
@ -817,15 +794,17 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(3, *buf.back().unwrap());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_back(&mut self, t: T) {
|
||||
pub fn push_back(&mut self, value: T) {
|
||||
if self.is_full() {
|
||||
self.reserve(1);
|
||||
let old_cap = self.cap();
|
||||
self.buf.double();
|
||||
unsafe { self.handle_cap_increase(old_cap); }
|
||||
debug_assert!(!self.is_full());
|
||||
}
|
||||
|
||||
let head = self.head;
|
||||
self.head = self.wrap_add(self.head, 1);
|
||||
unsafe { self.buffer_write(head, t) }
|
||||
unsafe { self.buffer_write(head, value) }
|
||||
}
|
||||
|
||||
/// Removes the last element from a buffer and returns it, or `None` if
|
||||
@ -858,8 +837,8 @@ impl<T> VecDeque<T> {
|
||||
self.tail <= self.head
|
||||
}
|
||||
|
||||
/// Removes an element from anywhere in the ringbuf and returns it, replacing it with the last
|
||||
/// element.
|
||||
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
|
||||
/// last element.
|
||||
///
|
||||
/// This does not preserve ordering, but is O(1).
|
||||
///
|
||||
@ -892,7 +871,7 @@ impl<T> VecDeque<T> {
|
||||
self.pop_back()
|
||||
}
|
||||
|
||||
/// Removes an element from anywhere in the ringbuf and returns it,
|
||||
/// Removes an element from anywhere in the `VecDeque` and returns it,
|
||||
/// replacing it with the first element.
|
||||
///
|
||||
/// This does not preserve ordering, but is O(1).
|
||||
@ -926,13 +905,13 @@ impl<T> VecDeque<T> {
|
||||
self.pop_front()
|
||||
}
|
||||
|
||||
/// Inserts an element at position `i` within the ringbuf. Whichever
|
||||
/// Inserts an element at `index` within the `VecDeque`. Whichever
|
||||
/// end is closer to the insertion point will be moved to make room,
|
||||
/// and all the affected elements will be moved to new positions.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `i` is greater than ringbuf's length
|
||||
/// Panics if `index` is greater than `VecDeque`'s length
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
@ -942,13 +921,15 @@ impl<T> VecDeque<T> {
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// buf.push_back(10);
|
||||
/// buf.push_back(12);
|
||||
/// buf.insert(1,11);
|
||||
/// buf.insert(1, 11);
|
||||
/// assert_eq!(Some(&11), buf.get(1));
|
||||
/// ```
|
||||
pub fn insert(&mut self, i: usize, t: T) {
|
||||
assert!(i <= self.len(), "index out of bounds");
|
||||
pub fn insert(&mut self, index: usize, value: T) {
|
||||
assert!(index <= self.len(), "index out of bounds");
|
||||
if self.is_full() {
|
||||
self.reserve(1);
|
||||
let old_cap = self.cap();
|
||||
self.buf.double();
|
||||
unsafe { self.handle_cap_increase(old_cap); }
|
||||
debug_assert!(!self.is_full());
|
||||
}
|
||||
|
||||
@ -974,15 +955,15 @@ impl<T> VecDeque<T> {
|
||||
// A - The element that should be after the insertion point
|
||||
// M - Indicates element was moved
|
||||
|
||||
let idx = self.wrap_add(self.tail, i);
|
||||
let idx = self.wrap_add(self.tail, index);
|
||||
|
||||
let distance_to_tail = i;
|
||||
let distance_to_head = self.len() - i;
|
||||
let distance_to_tail = index;
|
||||
let distance_to_head = self.len() - index;
|
||||
|
||||
let contiguous = self.is_contiguous();
|
||||
|
||||
match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
|
||||
(true, true, _) if i == 0 => {
|
||||
(true, true, _) if index == 0 => {
|
||||
// push_front
|
||||
//
|
||||
// T
|
||||
@ -1018,8 +999,8 @@ impl<T> VecDeque<T> {
|
||||
let new_tail = self.wrap_sub(self.tail, 1);
|
||||
|
||||
self.copy(new_tail, self.tail, 1);
|
||||
// Already moved the tail, so we only copy `i - 1` elements.
|
||||
self.copy(self.tail, self.tail + 1, i - 1);
|
||||
// Already moved the tail, so we only copy `index - 1` elements.
|
||||
self.copy(self.tail, self.tail + 1, index - 1);
|
||||
|
||||
self.tail = new_tail;
|
||||
},
|
||||
@ -1046,7 +1027,7 @@ impl<T> VecDeque<T> {
|
||||
// [o o o o o o . . . . o o I A o o]
|
||||
// M M
|
||||
|
||||
self.copy(self.tail - 1, self.tail, i);
|
||||
self.copy(self.tail - 1, self.tail, index);
|
||||
self.tail -= 1;
|
||||
},
|
||||
(false, false, true) => unsafe {
|
||||
@ -1063,10 +1044,10 @@ impl<T> VecDeque<T> {
|
||||
self.copy(1, 0, self.head);
|
||||
|
||||
// copy last element into empty spot at bottom of buffer
|
||||
self.copy(0, self.cap - 1, 1);
|
||||
self.copy(0, self.cap() - 1, 1);
|
||||
|
||||
// move elements from idx to end forward not including ^ element
|
||||
self.copy(idx + 1, idx, self.cap - 1 - idx);
|
||||
self.copy(idx + 1, idx, self.cap() - 1 - idx);
|
||||
|
||||
self.head += 1;
|
||||
},
|
||||
@ -1082,10 +1063,10 @@ impl<T> VecDeque<T> {
|
||||
// M M M
|
||||
|
||||
// copy elements up to new tail
|
||||
self.copy(self.tail - 1, self.tail, self.cap - self.tail);
|
||||
self.copy(self.tail - 1, self.tail, self.cap() - self.tail);
|
||||
|
||||
// copy last element into empty spot at bottom of buffer
|
||||
self.copy(self.cap - 1, 0, 1);
|
||||
self.copy(self.cap() - 1, 0, 1);
|
||||
|
||||
self.tail -= 1;
|
||||
},
|
||||
@ -1100,10 +1081,10 @@ impl<T> VecDeque<T> {
|
||||
// M M M M M M
|
||||
|
||||
// copy elements up to new tail
|
||||
self.copy(self.tail - 1, self.tail, self.cap - self.tail);
|
||||
self.copy(self.tail - 1, self.tail, self.cap() - self.tail);
|
||||
|
||||
// copy last element into empty spot at bottom of buffer
|
||||
self.copy(self.cap - 1, 0, 1);
|
||||
self.copy(self.cap() - 1, 0, 1);
|
||||
|
||||
// move elements from idx-1 to end forward not including ^ element
|
||||
self.copy(0, 1, idx - 1);
|
||||
@ -1126,16 +1107,16 @@ impl<T> VecDeque<T> {
|
||||
}
|
||||
|
||||
// tail might've been changed so we need to recalculate
|
||||
let new_idx = self.wrap_add(self.tail, i);
|
||||
let new_idx = self.wrap_add(self.tail, index);
|
||||
unsafe {
|
||||
self.buffer_write(new_idx, t);
|
||||
self.buffer_write(new_idx, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes and returns the element at position `i` from the ringbuf.
|
||||
/// Removes and returns the element at `index` from the `VecDeque`.
|
||||
/// Whichever end is closer to the removal point will be moved to make
|
||||
/// room, and all the affected elements will be moved to new positions.
|
||||
/// Returns `None` if `i` is out of bounds.
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
@ -1150,8 +1131,8 @@ impl<T> VecDeque<T> {
|
||||
/// assert_eq!(Some(&15), buf.get(2));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove(&mut self, i: usize) -> Option<T> {
|
||||
if self.is_empty() || self.len() <= i {
|
||||
pub fn remove(&mut self, index: usize) -> Option<T> {
|
||||
if self.is_empty() || self.len() <= index {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -1173,14 +1154,14 @@ impl<T> VecDeque<T> {
|
||||
// R - Indicates element that is being removed
|
||||
// M - Indicates element was moved
|
||||
|
||||
let idx = self.wrap_add(self.tail, i);
|
||||
let idx = self.wrap_add(self.tail, index);
|
||||
|
||||
let elem = unsafe {
|
||||
Some(self.buffer_read(idx))
|
||||
};
|
||||
|
||||
let distance_to_tail = i;
|
||||
let distance_to_head = self.len() - i;
|
||||
let distance_to_tail = index;
|
||||
let distance_to_head = self.len() - index;
|
||||
|
||||
let contiguous = self.is_contiguous();
|
||||
|
||||
@ -1195,7 +1176,7 @@ impl<T> VecDeque<T> {
|
||||
// [. . . . o o o o o o . . . . . .]
|
||||
// M M
|
||||
|
||||
self.copy(self.tail + 1, self.tail, i);
|
||||
self.copy(self.tail + 1, self.tail, index);
|
||||
self.tail += 1;
|
||||
},
|
||||
(true, false, _) => unsafe {
|
||||
@ -1221,7 +1202,7 @@ impl<T> VecDeque<T> {
|
||||
// [o o o o o o . . . . . . o o o o]
|
||||
// M M
|
||||
|
||||
self.copy(self.tail + 1, self.tail, i);
|
||||
self.copy(self.tail + 1, self.tail, index);
|
||||
self.tail = self.wrap_add(self.tail, 1);
|
||||
},
|
||||
(false, false, false) => unsafe {
|
||||
@ -1257,12 +1238,12 @@ impl<T> VecDeque<T> {
|
||||
// M
|
||||
|
||||
// draw in elements in the tail section
|
||||
self.copy(idx, idx + 1, self.cap - idx - 1);
|
||||
self.copy(idx, idx + 1, self.cap() - idx - 1);
|
||||
|
||||
// Prevents underflow.
|
||||
if self.head != 0 {
|
||||
// copy first element into empty spot
|
||||
self.copy(self.cap - 1, 0, 1);
|
||||
self.copy(self.cap() - 1, 0, 1);
|
||||
|
||||
// move elements in the head section backwards
|
||||
self.copy(0, 1, self.head - 1);
|
||||
@ -1284,10 +1265,10 @@ impl<T> VecDeque<T> {
|
||||
self.copy(1, 0, idx);
|
||||
|
||||
// copy last element into empty spot
|
||||
self.copy(0, self.cap - 1, 1);
|
||||
self.copy(0, self.cap() - 1, 1);
|
||||
|
||||
// move elements from tail to end forward, excluding the last one
|
||||
self.copy(self.tail + 1, self.tail, self.cap - self.tail - 1);
|
||||
self.copy(self.tail + 1, self.tail, self.cap() - self.tail - 1);
|
||||
|
||||
self.tail = self.wrap_add(self.tail, 1);
|
||||
}
|
||||
@ -1339,12 +1320,12 @@ impl<T> VecDeque<T> {
|
||||
let amount_in_first = first_len - at;
|
||||
|
||||
ptr::copy_nonoverlapping(first_half.as_ptr().offset(at as isize),
|
||||
*other.ptr,
|
||||
other.ptr(),
|
||||
amount_in_first);
|
||||
|
||||
// just take all of the second half.
|
||||
ptr::copy_nonoverlapping(second_half.as_ptr(),
|
||||
other.ptr.offset(amount_in_first as isize),
|
||||
other.ptr().offset(amount_in_first as isize),
|
||||
second_len);
|
||||
} else {
|
||||
// `at` lies in the second half, need to factor in the elements we skipped
|
||||
@ -1352,7 +1333,7 @@ impl<T> VecDeque<T> {
|
||||
let offset = at - first_len;
|
||||
let amount_in_second = second_len - offset;
|
||||
ptr::copy_nonoverlapping(second_half.as_ptr().offset(offset as isize),
|
||||
*other.ptr,
|
||||
other.ptr(),
|
||||
amount_in_second);
|
||||
}
|
||||
}
|
||||
@ -1428,7 +1409,7 @@ impl<T> VecDeque<T> {
|
||||
}
|
||||
|
||||
impl<T: Clone> VecDeque<T> {
|
||||
/// Modifies the ringbuf in-place so that `len()` is equal to new_len,
|
||||
/// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
|
||||
/// either by removing excess elements or by appending copies of a value to the back.
|
||||
///
|
||||
/// # Examples
|
||||
@ -1719,16 +1700,16 @@ impl<A> Index<usize> for VecDeque<A> {
|
||||
type Output = A;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, i: usize) -> &A {
|
||||
self.get(i).expect("Out of bounds access")
|
||||
fn index(&self, index: usize) -> &A {
|
||||
self.get(index).expect("Out of bounds access")
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A> IndexMut<usize> for VecDeque<A> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, i: usize) -> &mut A {
|
||||
self.get_mut(i).expect("Out of bounds access")
|
||||
fn index_mut(&mut self, index: usize) -> &mut A {
|
||||
self.get_mut(index).expect("Out of bounds access")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1900,8 +1881,8 @@ mod tests {
|
||||
assert_eq!(tester.swap_front_remove(idx), Some(len * 2 - 1 - i));
|
||||
}
|
||||
}
|
||||
assert!(tester.tail < tester.cap);
|
||||
assert!(tester.head < tester.cap);
|
||||
assert!(tester.tail < tester.cap());
|
||||
assert!(tester.head < tester.cap());
|
||||
assert_eq!(tester, expected);
|
||||
}
|
||||
}
|
||||
@ -1936,8 +1917,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
tester.insert(to_insert, to_insert);
|
||||
assert!(tester.tail < tester.cap);
|
||||
assert!(tester.head < tester.cap);
|
||||
assert!(tester.tail < tester.cap());
|
||||
assert!(tester.head < tester.cap());
|
||||
assert_eq!(tester, expected);
|
||||
}
|
||||
}
|
||||
@ -1973,8 +1954,8 @@ mod tests {
|
||||
tester.push_back(1234);
|
||||
}
|
||||
tester.remove(to_remove);
|
||||
assert!(tester.tail < tester.cap);
|
||||
assert!(tester.head < tester.cap);
|
||||
assert!(tester.tail < tester.cap());
|
||||
assert!(tester.head < tester.cap());
|
||||
assert_eq!(tester, expected);
|
||||
}
|
||||
}
|
||||
@ -2006,8 +1987,8 @@ mod tests {
|
||||
}
|
||||
tester.shrink_to_fit();
|
||||
assert!(tester.capacity() <= cap);
|
||||
assert!(tester.tail < tester.cap);
|
||||
assert!(tester.head < tester.cap);
|
||||
assert!(tester.tail < tester.cap());
|
||||
assert!(tester.head < tester.cap());
|
||||
assert_eq!(tester, expected);
|
||||
}
|
||||
}
|
||||
@ -2040,10 +2021,10 @@ mod tests {
|
||||
tester.push_back(i);
|
||||
}
|
||||
let result = tester.split_off(at);
|
||||
assert!(tester.tail < tester.cap);
|
||||
assert!(tester.head < tester.cap);
|
||||
assert!(result.tail < result.cap);
|
||||
assert!(result.head < result.cap);
|
||||
assert!(tester.tail < tester.cap());
|
||||
assert!(tester.head < tester.cap());
|
||||
assert!(result.tail < result.cap());
|
||||
assert!(result.head < result.cap());
|
||||
assert_eq!(tester, expected_self);
|
||||
assert_eq!(result, expected_other);
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(ascii)]
|
||||
#![feature(append)]
|
||||
#![feature(bit_vec_append_split_off)]
|
||||
#![feature(bitset)]
|
||||
#![feature(bitvec)]
|
||||
#![feature(box_syntax)]
|
||||
@ -37,14 +37,16 @@
|
||||
#![feature(rustc_private)]
|
||||
#![feature(slice_bytes)]
|
||||
#![feature(slice_chars)]
|
||||
#![feature(slice_extras)]
|
||||
#![feature(slice_splits)]
|
||||
#![feature(slice_position_elem)]
|
||||
#![feature(split_off)]
|
||||
#![feature(step_by)]
|
||||
#![feature(str_char)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(str_match_indices)]
|
||||
#![feature(str_split_at)]
|
||||
#![feature(str_utf16)]
|
||||
#![feature(box_str)]
|
||||
#![feature(subslice_offset)]
|
||||
#![feature(test)]
|
||||
#![feature(unboxed_closures)]
|
||||
@ -52,9 +54,10 @@
|
||||
#![feature(vec_deque_retain)]
|
||||
#![feature(vec_from_raw_buf)]
|
||||
#![feature(vec_push_all)]
|
||||
#![feature(vec_split_off)]
|
||||
#![feature(vecmap)]
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
extern crate collections;
|
||||
|
@ -119,71 +119,48 @@ fn test_first_mut() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tail() {
|
||||
fn test_split_first() {
|
||||
let mut a = vec![11];
|
||||
let b: &[i32] = &[];
|
||||
assert_eq!(a.tail(), b);
|
||||
assert!(b.split_first().is_none());
|
||||
assert_eq!(a.split_first(), Some((&11, b)));
|
||||
a = vec![11, 12];
|
||||
let b: &[i32] = &[12];
|
||||
assert_eq!(a.tail(), b);
|
||||
assert_eq!(a.split_first(), Some((&11, b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tail_mut() {
|
||||
fn test_split_first_mut() {
|
||||
let mut a = vec![11];
|
||||
let b: &mut [i32] = &mut [];
|
||||
assert!(a.tail_mut() == b);
|
||||
assert!(b.split_first_mut().is_none());
|
||||
assert!(a.split_first_mut() == Some((&mut 11, b)));
|
||||
a = vec![11, 12];
|
||||
let b: &mut [_] = &mut [12];
|
||||
assert!(a.tail_mut() == b);
|
||||
assert!(a.split_first_mut() == Some((&mut 11, b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_tail_empty() {
|
||||
let a = Vec::<i32>::new();
|
||||
a.tail();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_tail_mut_empty() {
|
||||
let mut a = Vec::<i32>::new();
|
||||
a.tail_mut();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init() {
|
||||
fn test_split_last() {
|
||||
let mut a = vec![11];
|
||||
let b: &[i32] = &[];
|
||||
assert_eq!(a.init(), b);
|
||||
assert!(b.split_last().is_none());
|
||||
assert_eq!(a.split_last(), Some((&11, b)));
|
||||
a = vec![11, 12];
|
||||
let b: &[_] = &[11];
|
||||
assert_eq!(a.init(), b);
|
||||
assert_eq!(a.split_last(), Some((&12, b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_mut() {
|
||||
fn test_split_last_mut() {
|
||||
let mut a = vec![11];
|
||||
let b: &mut [i32] = &mut [];
|
||||
assert!(a.init_mut() == b);
|
||||
assert!(b.split_last_mut().is_none());
|
||||
assert!(a.split_last_mut() == Some((&mut 11, b)));
|
||||
|
||||
a = vec![11, 12];
|
||||
let b: &mut [_] = &mut [11];
|
||||
assert!(a.init_mut() == b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_init_empty() {
|
||||
let a = Vec::<i32>::new();
|
||||
a.init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_init_mut_empty() {
|
||||
let mut a = Vec::<i32>::new();
|
||||
a.init_mut();
|
||||
assert!(a.split_last_mut() == Some((&mut 12, b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -606,22 +583,22 @@ fn test_concat() {
|
||||
assert_eq!(d, [1, 2, 3]);
|
||||
|
||||
let v: &[&[_]] = &[&[1], &[2, 3]];
|
||||
assert_eq!(v.connect(&0), [1, 0, 2, 3]);
|
||||
assert_eq!(v.join(&0), [1, 0, 2, 3]);
|
||||
let v: &[&[_]] = &[&[1], &[2], &[3]];
|
||||
assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]);
|
||||
assert_eq!(v.join(&0), [1, 0, 2, 0, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_connect() {
|
||||
fn test_join() {
|
||||
let v: [Vec<i32>; 0] = [];
|
||||
assert_eq!(v.connect(&0), []);
|
||||
assert_eq!([vec![1], vec![2, 3]].connect(&0), [1, 0, 2, 3]);
|
||||
assert_eq!([vec![1], vec![2], vec![3]].connect(&0), [1, 0, 2, 0, 3]);
|
||||
assert_eq!(v.join(&0), []);
|
||||
assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]);
|
||||
assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]);
|
||||
|
||||
let v: [&[_]; 2] = [&[1], &[2, 3]];
|
||||
assert_eq!(v.connect(&0), [1, 0, 2, 3]);
|
||||
assert_eq!(v.join(&0), [1, 0, 2, 3]);
|
||||
let v: [&[_]; 3] = [&[1], &[2], &[3]];
|
||||
assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]);
|
||||
assert_eq!(v.join(&0), [1, 0, 2, 0, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1318,7 +1295,7 @@ mod bench {
|
||||
|
||||
#[bench]
|
||||
fn mut_iterator(b: &mut Bencher) {
|
||||
let mut v: Vec<_> = repeat(0).take(100).collect();
|
||||
let mut v = vec![0; 100];
|
||||
|
||||
b.iter(|| {
|
||||
let mut i = 0;
|
||||
@ -1339,11 +1316,11 @@ mod bench {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn connect(b: &mut Bencher) {
|
||||
fn join(b: &mut Bencher) {
|
||||
let xss: Vec<Vec<i32>> =
|
||||
(0..100).map(|i| (0..i).collect()).collect();
|
||||
b.iter(|| {
|
||||
xss.connect(&0)
|
||||
xss.join(&0)
|
||||
});
|
||||
}
|
||||
|
||||
@ -1419,7 +1396,7 @@ mod bench {
|
||||
#[bench]
|
||||
fn zero_1kb_from_elem(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
repeat(0u8).take(1024).collect::<Vec<_>>()
|
||||
vec![0u8; 1024]
|
||||
});
|
||||
}
|
||||
|
||||
@ -1467,7 +1444,7 @@ mod bench {
|
||||
fn random_inserts(b: &mut Bencher) {
|
||||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut v: Vec<_> = repeat((0, 0)).take(30).collect();
|
||||
let mut v = vec![(0, 0); 30];
|
||||
for _ in 0..100 {
|
||||
let l = v.len();
|
||||
v.insert(rng.gen::<usize>() % (l + 1),
|
||||
@ -1479,7 +1456,7 @@ mod bench {
|
||||
fn random_removes(b: &mut Bencher) {
|
||||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut v: Vec<_> = repeat((0, 0)).take(130).collect();
|
||||
let mut v = vec![(0, 0); 130];
|
||||
for _ in 0..100 {
|
||||
let l = v.len();
|
||||
v.remove(rng.gen::<usize>() % l);
|
||||
|
@ -158,32 +158,32 @@ fn test_concat_for_different_lengths() {
|
||||
test_concat!("abc", ["", "a", "bc"]);
|
||||
}
|
||||
|
||||
macro_rules! test_connect {
|
||||
macro_rules! test_join {
|
||||
($expected: expr, $string: expr, $delim: expr) => {
|
||||
{
|
||||
let s = $string.connect($delim);
|
||||
let s = $string.join($delim);
|
||||
assert_eq!($expected, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_connect_for_different_types() {
|
||||
test_connect!("a-b", ["a", "b"], "-");
|
||||
fn test_join_for_different_types() {
|
||||
test_join!("a-b", ["a", "b"], "-");
|
||||
let hyphen = "-".to_string();
|
||||
test_connect!("a-b", [s("a"), s("b")], &*hyphen);
|
||||
test_connect!("a-b", vec!["a", "b"], &*hyphen);
|
||||
test_connect!("a-b", &*vec!["a", "b"], "-");
|
||||
test_connect!("a-b", vec![s("a"), s("b")], "-");
|
||||
test_join!("a-b", [s("a"), s("b")], &*hyphen);
|
||||
test_join!("a-b", vec!["a", "b"], &*hyphen);
|
||||
test_join!("a-b", &*vec!["a", "b"], "-");
|
||||
test_join!("a-b", vec![s("a"), s("b")], "-");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_connect_for_different_lengths() {
|
||||
fn test_join_for_different_lengths() {
|
||||
let empty: &[&str] = &[];
|
||||
test_connect!("", empty, "-");
|
||||
test_connect!("a", ["a"], "-");
|
||||
test_connect!("a-b", ["a", "b"], "-");
|
||||
test_connect!("-a-bc", ["", "a", "bc"], "-");
|
||||
test_join!("", empty, "-");
|
||||
test_join!("a", ["a"], "-");
|
||||
test_join!("a-b", ["a", "b"], "-");
|
||||
test_join!("-a-bc", ["", "a", "bc"], "-");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -701,11 +701,23 @@ fn test_split_at() {
|
||||
assert_eq!(b, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_at_mut() {
|
||||
use std::ascii::AsciiExt;
|
||||
let mut s = "Hello World".to_string();
|
||||
{
|
||||
let (a, b) = s.split_at_mut(5);
|
||||
a.make_ascii_uppercase();
|
||||
b.make_ascii_lowercase();
|
||||
}
|
||||
assert_eq!(s, "HELLO world");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_split_at_boundscheck() {
|
||||
let s = "ศไทย中华Việt Nam";
|
||||
let (a, b) = s.split_at(1);
|
||||
s.split_at(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1746,6 +1758,14 @@ fn to_uppercase() {
|
||||
assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_string() {
|
||||
// The only way to acquire a Box<str> in the first place is through a String, so just
|
||||
// test that we can round-trip between Box<str> and String.
|
||||
let string = String::from("Some text goes here");
|
||||
assert_eq!(string.clone().into_boxed_slice().into_string(), string);
|
||||
}
|
||||
|
||||
mod pattern {
|
||||
use std::str::pattern::Pattern;
|
||||
use std::str::pattern::{Searcher, ReverseSearcher};
|
||||
@ -1820,6 +1840,14 @@ mod pattern {
|
||||
Match (4, 6),
|
||||
Reject(6, 7),
|
||||
]);
|
||||
make_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", [
|
||||
Reject(0, 1),
|
||||
Match (1, 3),
|
||||
Reject(3, 4),
|
||||
Match (4, 6),
|
||||
Match (6, 8),
|
||||
Reject(8, 9),
|
||||
]);
|
||||
make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [
|
||||
Match (0, 0),
|
||||
Reject(0, 1),
|
||||
@ -2073,12 +2101,12 @@ mod bench {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_connect(b: &mut Bencher) {
|
||||
fn bench_join(b: &mut Bencher) {
|
||||
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
|
||||
let sep = "→";
|
||||
let v = vec![s, s, s, s, s, s, s, s, s, s];
|
||||
b.iter(|| {
|
||||
assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9);
|
||||
assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -10,18 +10,9 @@
|
||||
|
||||
use std::borrow::{IntoCow, Cow};
|
||||
use std::iter::repeat;
|
||||
#[allow(deprecated)]
|
||||
use std::string::as_string;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_as_string() {
|
||||
let x = "foo";
|
||||
assert_eq!(x, &**as_string(x));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
let owned: Option<::std::string::String> = "string".parse().ok();
|
||||
@ -374,6 +365,13 @@ fn test_extend_ref() {
|
||||
assert_eq!(&a, "foobar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_boxed_slice() {
|
||||
let xs = String::from("hello my name is bob");
|
||||
let ys = xs.into_boxed_slice();
|
||||
assert_eq!(&*ys, "hello my name is bob");
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_with_capacity(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
use std::iter::{FromIterator, repeat};
|
||||
use std::mem::size_of;
|
||||
#[allow(deprecated)]
|
||||
use std::vec::as_vec;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
@ -25,25 +23,6 @@ impl<'a> Drop for DropCounter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_as_vec() {
|
||||
let xs = [1u8, 2u8, 3u8];
|
||||
assert_eq!(&**as_vec(&xs), xs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_as_vec_dtor() {
|
||||
let (mut count_x, mut count_y) = (0, 0);
|
||||
{
|
||||
let xs = &[DropCounter { count: &mut count_x }, DropCounter { count: &mut count_y }];
|
||||
assert_eq!(as_vec(xs).len(), 2);
|
||||
}
|
||||
assert_eq!(count_x, 1);
|
||||
assert_eq!(count_y, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_small_vec_struct() {
|
||||
assert!(size_of::<Vec<u8>>() == size_of::<usize>() * 3);
|
||||
|
@ -8,15 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Traits for dynamic typing of any `'static` type (through runtime reflection)
|
||||
//!
|
||||
//! This module implements the `Any` trait, which enables dynamic typing
|
||||
//! of any `'static` type through runtime reflection.
|
||||
//!
|
||||
//! `Any` itself can be used to get a `TypeId`, and has more features when used
|
||||
//! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and
|
||||
//! `as_ref` methods, to test if the contained value is of a given type, and to
|
||||
//! get a reference to the inner value as a type. As`&mut Any`, there is also
|
||||
//! get a reference to the inner value as a type. As `&mut Any`, there is also
|
||||
//! the `as_mut` method, for getting a mutable reference to the inner value.
|
||||
//! `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the
|
||||
//! object. See the extension traits (`*Ext`) for the full details.
|
||||
|
@ -11,8 +11,9 @@
|
||||
//! Implementations of things like `Eq` for fixed-length arrays
|
||||
//! up to a certain length. Eventually we should able to generalize
|
||||
//! to all lengths.
|
||||
//!
|
||||
//! *[See also the array primitive type](../primitive.array.html).*
|
||||
|
||||
#![doc(primitive = "array")]
|
||||
#![unstable(feature = "fixed_size_array",
|
||||
reason = "traits and impls are better expressed through generic \
|
||||
integer constants")]
|
||||
|
@ -78,6 +78,7 @@ use intrinsics;
|
||||
use cell::UnsafeCell;
|
||||
|
||||
use default::Default;
|
||||
use fmt;
|
||||
|
||||
/// A boolean type which can be safely shared between threads.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -272,13 +273,13 @@ impl AtomicBool {
|
||||
unsafe { atomic_swap(self.v.get(), val, order) > 0 }
|
||||
}
|
||||
|
||||
/// Stores a value into the bool if the current value is the same as the expected value.
|
||||
/// Stores a value into the `bool` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `old`, then the value was
|
||||
/// updated.
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
///
|
||||
/// `swap` also takes an `Ordering` argument which describes the memory ordering of this
|
||||
/// operation.
|
||||
/// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
|
||||
/// this operation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -295,11 +296,11 @@ impl AtomicBool {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool {
|
||||
let old = if old { UINT_TRUE } else { 0 };
|
||||
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
|
||||
let current = if current { UINT_TRUE } else { 0 };
|
||||
let new = if new { UINT_TRUE } else { 0 };
|
||||
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 }
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) > 0 }
|
||||
}
|
||||
|
||||
/// Logical "and" with a boolean value.
|
||||
@ -515,10 +516,10 @@ impl AtomicIsize {
|
||||
unsafe { atomic_swap(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Stores a value into the isize if the current value is the same as the expected value.
|
||||
/// Stores a value into the `isize` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `old`, then the value was
|
||||
/// updated.
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
///
|
||||
/// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
|
||||
/// this operation.
|
||||
@ -538,8 +539,8 @@ impl AtomicIsize {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize {
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
|
||||
pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize {
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) }
|
||||
}
|
||||
|
||||
/// Add an isize to the current value, returning the previous value.
|
||||
@ -709,10 +710,10 @@ impl AtomicUsize {
|
||||
unsafe { atomic_swap(self.v.get(), val, order) }
|
||||
}
|
||||
|
||||
/// Stores a value into the usize if the current value is the same as the expected value.
|
||||
/// Stores a value into the `usize` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `old`, then the value was
|
||||
/// updated.
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
///
|
||||
/// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
|
||||
/// this operation.
|
||||
@ -732,8 +733,8 @@ impl AtomicUsize {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize {
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
|
||||
pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize {
|
||||
unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) }
|
||||
}
|
||||
|
||||
/// Add to the current usize, returning the previous value.
|
||||
@ -910,10 +911,10 @@ impl<T> AtomicPtr<T> {
|
||||
unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
|
||||
}
|
||||
|
||||
/// Stores a value into the pointer if the current value is the same as the expected value.
|
||||
/// Stores a value into the pointer if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `old`, then the value was
|
||||
/// updated.
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
///
|
||||
/// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
|
||||
/// this operation.
|
||||
@ -933,9 +934,9 @@ impl<T> AtomicPtr<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
|
||||
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
|
||||
unsafe {
|
||||
atomic_compare_and_swap(self.p.get() as *mut usize, old as usize,
|
||||
atomic_compare_and_swap(self.p.get() as *mut usize, current as usize,
|
||||
new as usize, order) as *mut T
|
||||
}
|
||||
}
|
||||
@ -953,7 +954,6 @@ unsafe fn atomic_store<T>(dst: *mut T, val: T, order:Ordering) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_load<T>(dst: *const T, order:Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_load_acq(dst),
|
||||
@ -965,7 +965,6 @@ unsafe fn atomic_load<T>(dst: *const T, order:Ordering) -> T {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_xchg_acq(dst, val),
|
||||
@ -978,7 +977,6 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
|
||||
/// Returns the old value (like __sync_fetch_and_add).
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_xadd_acq(dst, val),
|
||||
@ -991,7 +989,6 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
|
||||
/// Returns the old value (like __sync_fetch_and_sub).
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_xsub_acq(dst, val),
|
||||
@ -1003,7 +1000,6 @@ unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_compare_and_swap<T>(dst: *mut T, old:T, new:T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
|
||||
@ -1015,7 +1011,6 @@ unsafe fn atomic_compare_and_swap<T>(dst: *mut T, old:T, new:T, order: Ordering)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_and_acq(dst, val),
|
||||
@ -1027,7 +1022,6 @@ unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_nand_acq(dst, val),
|
||||
@ -1040,7 +1034,6 @@ unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_or_acq(dst, val),
|
||||
@ -1053,7 +1046,6 @@ unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||
match order {
|
||||
Acquire => intrinsics::atomic_xor_acq(dst, val),
|
||||
@ -1098,3 +1090,23 @@ pub fn fence(order: Ordering) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_Debug {
|
||||
($($t:ident)*) => ($(
|
||||
#[stable(feature = "atomic_debug", since = "1.3.0")]
|
||||
impl fmt::Debug for $t {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple(stringify!($t)).field(&self.load(Ordering::SeqCst)).finish()
|
||||
}
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
impl_Debug!{ AtomicUsize AtomicIsize AtomicBool }
|
||||
|
||||
#[stable(feature = "atomic_debug", since = "1.3.0")]
|
||||
impl<T> fmt::Debug for AtomicPtr<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish()
|
||||
}
|
||||
}
|
||||
|
@ -36,16 +36,16 @@
|
||||
//! would otherwise be disallowed though, there are occasions when interior mutability might be
|
||||
//! appropriate, or even *must* be used, e.g.
|
||||
//!
|
||||
//! * Introducing inherited mutability roots to shared types.
|
||||
//! * Introducing mutability 'inside' of something immutable
|
||||
//! * Implementation details of logically-immutable methods.
|
||||
//! * Mutating implementations of `Clone`.
|
||||
//!
|
||||
//! ## Introducing inherited mutability roots to shared types
|
||||
//! ## Introducing mutability 'inside' of something immutable
|
||||
//!
|
||||
//! Shared smart pointer types, including `Rc<T>` and `Arc<T>`, provide containers that can be
|
||||
//! Many shared smart pointer types, including `Rc<T>` and `Arc<T>`, provide containers that can be
|
||||
//! cloned and shared between multiple parties. Because the contained values may be
|
||||
//! multiply-aliased, they can only be borrowed as shared references, not mutable references.
|
||||
//! Without cells it would be impossible to mutate data inside of shared boxes at all!
|
||||
//! multiply-aliased, they can only be borrowed with `&`, not `&mut`. Without cells it would be
|
||||
//! impossible to mutate data inside of these smart pointers at all.
|
||||
//!
|
||||
//! It's very common then to put a `RefCell<T>` inside shared pointer types to reintroduce
|
||||
//! mutability:
|
||||
@ -65,8 +65,8 @@
|
||||
//! ```
|
||||
//!
|
||||
//! Note that this example uses `Rc<T>` and not `Arc<T>`. `RefCell<T>`s are for single-threaded
|
||||
//! scenarios. Consider using `Mutex<T>` if you need shared mutability in a multi-threaded
|
||||
//! situation.
|
||||
//! scenarios. Consider using `RwLock<T>` or `Mutex<T>` if you need shared mutability in a
|
||||
//! multi-threaded situation.
|
||||
//!
|
||||
//! ## Implementation details of logically-immutable methods
|
||||
//!
|
||||
|
@ -13,7 +13,6 @@
|
||||
//! For more details, see ::rustc_unicode::char (a.k.a. std::char)
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
#![doc(primitive = "char")]
|
||||
#![stable(feature = "core_char", since = "1.2.0")]
|
||||
|
||||
use iter::Iterator;
|
||||
@ -85,10 +84,18 @@ pub fn from_u32(i: u32) -> Option<char> {
|
||||
if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { transmute(i) })
|
||||
Some(unsafe { from_u32_unchecked(i) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `u32` to an `char`, not checking whether it is a valid unicode
|
||||
/// codepoint.
|
||||
#[inline]
|
||||
#[unstable(feature = "char_from_unchecked", reason = "recently added API")]
|
||||
pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
transmute(i)
|
||||
}
|
||||
|
||||
/// Converts a number to the character representing it.
|
||||
///
|
||||
/// # Return value
|
||||
@ -116,12 +123,11 @@ pub fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
panic!("from_digit: radix is too high (maximum 36)");
|
||||
}
|
||||
if num < radix {
|
||||
unsafe {
|
||||
if num < 10 {
|
||||
Some(transmute('0' as u32 + num))
|
||||
} else {
|
||||
Some(transmute('a' as u32 + num - 10))
|
||||
}
|
||||
let num = num as u8;
|
||||
if num < 10 {
|
||||
Some((b'0' + num) as char)
|
||||
} else {
|
||||
Some((b'a' + num - 10) as char)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -319,16 +325,13 @@ impl Iterator for EscapeUnicode {
|
||||
Some('{')
|
||||
}
|
||||
EscapeUnicodeState::Value(offset) => {
|
||||
let v = match ((self.c as i32) >> (offset * 4)) & 0xf {
|
||||
i @ 0 ... 9 => '0' as i32 + i,
|
||||
i => 'a' as i32 + (i - 10)
|
||||
};
|
||||
let c = from_digit(((self.c as u32) >> (offset * 4)) & 0xf, 16).unwrap();
|
||||
if offset == 0 {
|
||||
self.state = EscapeUnicodeState::RightBrace;
|
||||
} else {
|
||||
self.state = EscapeUnicodeState::Value(offset - 1);
|
||||
}
|
||||
Some(unsafe { transmute(v) })
|
||||
Some(c)
|
||||
}
|
||||
EscapeUnicodeState::RightBrace => {
|
||||
self.state = EscapeUnicodeState::Done;
|
||||
|
@ -166,6 +166,8 @@ impl Ordering {
|
||||
///
|
||||
/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and
|
||||
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
|
||||
///
|
||||
/// When this trait is `derive`d, it produces a lexicographic ordering.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Ord: Eq + PartialOrd<Self> {
|
||||
/// This method returns an `Ordering` between `self` and `other`.
|
||||
|
@ -175,6 +175,12 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
|
||||
fn is_pretty(&self) -> bool {
|
||||
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
|
||||
}
|
||||
|
||||
/// Returns the wrapped `Formatter`.
|
||||
#[unstable(feature = "debug_builder_formatter", reason = "recently added")]
|
||||
pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> {
|
||||
&mut self.fmt
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugInner<'a, 'b: 'a> {
|
||||
|
@ -267,11 +267,18 @@ impl<'a> Display for Arguments<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Format trait for the `:?` format. Useful for debugging, all types
|
||||
/// should implement this.
|
||||
/// Format trait for the `?` character.
|
||||
///
|
||||
/// `Debug` should format the output in a programmer-facing, debugging context.
|
||||
///
|
||||
/// Generally speaking, you should just `derive` a `Debug` implementation.
|
||||
///
|
||||
/// When used with the alternate format specifier `#?`, the output is pretty-printed.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Deriving an implementation:
|
||||
@ -309,10 +316,42 @@ impl<'a> Display for Arguments<'a> {
|
||||
/// println!("The origin is: {:?}", origin);
|
||||
/// ```
|
||||
///
|
||||
/// This outputs:
|
||||
///
|
||||
/// ```text
|
||||
/// The origin is: Point { x: 0, y: 0 }
|
||||
/// ```
|
||||
///
|
||||
/// There are a number of `debug_*` methods on `Formatter` to help you with manual
|
||||
/// implementations, such as [`debug_struct`][debug_struct].
|
||||
///
|
||||
/// `Debug` implementations using either `derive` or the debug builder API
|
||||
/// on `Formatter` support pretty printing using the alternate flag: `{:#?}`.
|
||||
///
|
||||
/// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct
|
||||
///
|
||||
/// Pretty printing with `#?`:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Debug)]
|
||||
/// struct Point {
|
||||
/// x: i32,
|
||||
/// y: i32,
|
||||
/// }
|
||||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// println!("The origin is: {:#?}", origin);
|
||||
/// ```
|
||||
///
|
||||
/// This outputs:
|
||||
///
|
||||
/// ```text
|
||||
/// The origin is: Point {
|
||||
/// x: 0,
|
||||
/// y: 0
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
|
||||
defined in your crate, add `#[derive(Debug)]` or \
|
||||
@ -324,8 +363,39 @@ pub trait Debug {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// When a value can be semantically expressed as a String, this trait may be
|
||||
/// used. It corresponds to the default format, `{}`.
|
||||
/// Format trait for an empty format, `{}`.
|
||||
///
|
||||
/// `Display` is similar to [`Debug`][debug], but `Display` is for user-facing
|
||||
/// output, and so cannot be derived.
|
||||
///
|
||||
/// [debug]: trait.Debug.html
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Implementing `Display` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Point {
|
||||
/// x: i32,
|
||||
/// y: i32,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for Point {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// write!(f, "({}, {})", self.x, self.y)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let origin = Point { x: 0, y: 0 };
|
||||
///
|
||||
/// println!("The origin is: {}", origin);
|
||||
/// ```
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
|
||||
formatter; try using `:?` instead if you are using \
|
||||
a format string"]
|
||||
@ -336,7 +406,46 @@ pub trait Display {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `o` character
|
||||
/// Format trait for the `o` character.
|
||||
///
|
||||
/// The `Octal` trait should format its output as a number in base-8.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0o` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42; // 42 is '52' in octal
|
||||
///
|
||||
/// assert_eq!(format!("{:o}", x), "52");
|
||||
/// assert_eq!(format!("{:#o}", x), "0o52");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Octal` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::Octal for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
///
|
||||
/// write!(f, "{:o}", val) // delegate to i32's implementation
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(9);
|
||||
///
|
||||
/// println!("l as octal is: {:o}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Octal {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -344,7 +453,46 @@ pub trait Octal {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `b` character
|
||||
/// Format trait for the `b` character.
|
||||
///
|
||||
/// The `Binary` trait should format its output as a number in binary.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0b` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42; // 42 is '101010' in binary
|
||||
///
|
||||
/// assert_eq!(format!("{:b}", x), "101010");
|
||||
/// assert_eq!(format!("{:#b}", x), "0b101010");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Binary` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::Binary for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
///
|
||||
/// write!(f, "{:b}", val) // delegate to i32's implementation
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(107);
|
||||
///
|
||||
/// println!("l as binary is: {:b}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Binary {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -352,7 +500,47 @@ pub trait Binary {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `x` character
|
||||
/// Format trait for the `x` character.
|
||||
///
|
||||
/// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f`
|
||||
/// in lower case.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0x` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42; // 42 is '2a' in hex
|
||||
///
|
||||
/// assert_eq!(format!("{:x}", x), "2a");
|
||||
/// assert_eq!(format!("{:#x}", x), "0x2a");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `LowerHex` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::LowerHex for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
///
|
||||
/// write!(f, "{:x}", val) // delegate to i32's implementation
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(9);
|
||||
///
|
||||
/// println!("l as hex is: {:x}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait LowerHex {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -360,7 +548,47 @@ pub trait LowerHex {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `X` character
|
||||
/// Format trait for the `X` character.
|
||||
///
|
||||
/// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F`
|
||||
/// in upper case.
|
||||
///
|
||||
/// The alternate flag, `#`, adds a `0x` in front of the output.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42; // 42 is '2A' in hex
|
||||
///
|
||||
/// assert_eq!(format!("{:X}", x), "2A");
|
||||
/// assert_eq!(format!("{:#X}", x), "0x2A");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `UpperHex` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::UpperHex for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
///
|
||||
/// write!(f, "{:X}", val) // delegate to i32's implementation
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(9);
|
||||
///
|
||||
/// println!("l as hex is: {:X}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait UpperHex {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -368,7 +596,44 @@ pub trait UpperHex {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `p` character
|
||||
/// Format trait for the `p` character.
|
||||
///
|
||||
/// The `Pointer` trait should format its output as a memory location. This is commonly presented
|
||||
/// as hexidecimal.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `&i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = &42;
|
||||
///
|
||||
/// let address = format!("{:p}", x); // this produces something like '0x7f06092ac6d0'
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Pointer` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::Pointer for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// // use `as` to convert to a `*const T`, which implements Pointer, which we can use
|
||||
///
|
||||
/// write!(f, "{:p}", self as *const Length)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(42);
|
||||
///
|
||||
/// println!("l is in memory here: {:p}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Pointer {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -376,7 +641,42 @@ pub trait Pointer {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `e` character
|
||||
/// Format trait for the `e` character.
|
||||
///
|
||||
/// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `i32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
|
||||
///
|
||||
/// assert_eq!(format!("{:e}", x), "4.2e1");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `LowerExp` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::LowerExp for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
/// write!(f, "{}e1", val / 10)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(100);
|
||||
///
|
||||
/// println!("l in scientific notation is: {:e}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait LowerExp {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -384,7 +684,42 @@ pub trait LowerExp {
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `E` character
|
||||
/// Format trait for the `E` character.
|
||||
///
|
||||
/// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`.
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// [module]: ../index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage with `f32`:
|
||||
///
|
||||
/// ```
|
||||
/// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
|
||||
///
|
||||
/// assert_eq!(format!("{:E}", x), "4.2E1");
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `UpperExp` on a type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// struct Length(i32);
|
||||
///
|
||||
/// impl fmt::UpperExp for Length {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// let val = self.0;
|
||||
/// write!(f, "{}E1", val / 10)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let l = Length(100);
|
||||
///
|
||||
/// println!("l in scientific notation is: {:E}", l);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait UpperExp {
|
||||
/// Formats the value using the given formatter.
|
||||
@ -980,7 +1315,14 @@ impl Debug for char {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Display for char {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.write_char(*self)
|
||||
if f.width.is_none() && f.precision.is_none() {
|
||||
f.write_char(*self)
|
||||
} else {
|
||||
let mut utf8 = [0; 4];
|
||||
let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
|
||||
let s: &str = unsafe { mem::transmute(&utf8[..amt]) };
|
||||
f.pad(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1146,20 +1488,19 @@ macro_rules! tuple {
|
||||
impl<$($name:Debug),*> Debug for ($($name,)*) {
|
||||
#[allow(non_snake_case, unused_assignments)]
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
try!(write!(f, "("));
|
||||
let mut builder = f.debug_tuple("");
|
||||
let ($(ref $name,)*) = *self;
|
||||
let mut n = 0;
|
||||
$(
|
||||
if n > 0 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
try!(write!(f, "{:?}", *$name));
|
||||
builder.field($name);
|
||||
n += 1;
|
||||
)*
|
||||
|
||||
if n == 1 {
|
||||
try!(write!(f, ","));
|
||||
try!(write!(builder.formatter(), ","));
|
||||
}
|
||||
write!(f, ")")
|
||||
|
||||
builder.finish()
|
||||
}
|
||||
}
|
||||
peel! { $($name,)* }
|
||||
|
@ -12,26 +12,31 @@
|
||||
|
||||
// FIXME: #6220 Implement floating point formatting
|
||||
|
||||
#![allow(unsigned_negation)]
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use fmt;
|
||||
use num::Zero;
|
||||
use ops::{Div, Rem, Sub};
|
||||
use str;
|
||||
use slice;
|
||||
use ptr;
|
||||
use mem;
|
||||
|
||||
#[doc(hidden)]
|
||||
trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
|
||||
Sub<Output=Self> + Copy {
|
||||
fn from_u8(u: u8) -> Self;
|
||||
fn to_u8(&self) -> u8;
|
||||
fn to_u32(&self) -> u32;
|
||||
fn to_u64(&self) -> u64;
|
||||
}
|
||||
|
||||
macro_rules! doit {
|
||||
($($t:ident)*) => ($(impl Int for $t {
|
||||
fn from_u8(u: u8) -> $t { u as $t }
|
||||
fn to_u8(&self) -> u8 { *self as u8 }
|
||||
fn to_u32(&self) -> u32 { *self as u32 }
|
||||
fn to_u64(&self) -> u64 { *self as u64 }
|
||||
})*)
|
||||
}
|
||||
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
|
||||
@ -188,6 +193,7 @@ macro_rules! radix_fmt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! int_base {
|
||||
($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -209,9 +215,9 @@ macro_rules! debug {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! integer {
|
||||
($Int:ident, $Uint:ident) => {
|
||||
int_base! { Display for $Int as $Int -> Decimal }
|
||||
int_base! { Binary for $Int as $Uint -> Binary }
|
||||
int_base! { Octal for $Int as $Uint -> Octal }
|
||||
int_base! { LowerHex for $Int as $Uint -> LowerHex }
|
||||
@ -219,7 +225,6 @@ macro_rules! integer {
|
||||
radix_fmt! { $Int as $Int, fmt_int }
|
||||
debug! { $Int }
|
||||
|
||||
int_base! { Display for $Uint as $Uint -> Decimal }
|
||||
int_base! { Binary for $Uint as $Uint -> Binary }
|
||||
int_base! { Octal for $Uint as $Uint -> Octal }
|
||||
int_base! { LowerHex for $Uint as $Uint -> LowerHex }
|
||||
@ -233,3 +238,80 @@ integer! { i8, u8 }
|
||||
integer! { i16, u16 }
|
||||
integer! { i32, u32 }
|
||||
integer! { i64, u64 }
|
||||
|
||||
const DEC_DIGITS_LUT: &'static[u8] =
|
||||
b"0001020304050607080910111213141516171819\
|
||||
2021222324252627282930313233343536373839\
|
||||
4041424344454647484950515253545556575859\
|
||||
6061626364656667686970717273747576777879\
|
||||
8081828384858687888990919293949596979899";
|
||||
|
||||
macro_rules! impl_Display {
|
||||
($($t:ident),*: $conv_fn:ident) => ($(
|
||||
impl fmt::Display for $t {
|
||||
#[allow(unused_comparisons)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let is_positive = *self >= 0;
|
||||
let mut n = if is_positive {
|
||||
self.$conv_fn()
|
||||
} else {
|
||||
// convert the negative num to positive by summing 1 to it's 2 complement
|
||||
(!self.$conv_fn()).wrapping_add(1)
|
||||
};
|
||||
let mut buf: [u8; 20] = unsafe { mem::uninitialized() };
|
||||
let mut curr = buf.len() as isize;
|
||||
let buf_ptr = buf.as_mut_ptr();
|
||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||
|
||||
unsafe {
|
||||
// eagerly decode 4 characters at a time
|
||||
if <$t>::max_value() as u64 >= 10000 {
|
||||
while n >= 10000 {
|
||||
let rem = (n % 10000) as isize;
|
||||
n /= 10000;
|
||||
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
|
||||
}
|
||||
}
|
||||
|
||||
// if we reach here numbers are <= 9999, so at most 4 chars long
|
||||
let mut n = n as isize; // possibly reduce 64bit math
|
||||
|
||||
// decode 2 more chars, if > 2 chars
|
||||
if n >= 100 {
|
||||
let d1 = (n % 100) << 1;
|
||||
n /= 100;
|
||||
curr -= 2;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
}
|
||||
|
||||
// decode last 1 or 2 chars
|
||||
if n < 10 {
|
||||
curr -= 1;
|
||||
*buf_ptr.offset(curr) = (n as u8) + 48;
|
||||
} else {
|
||||
let d1 = n << 1;
|
||||
curr -= 2;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
}
|
||||
}
|
||||
|
||||
let buf_slice = unsafe {
|
||||
str::from_utf8_unchecked(
|
||||
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
|
||||
};
|
||||
f.pad_integral(is_positive, "", buf_slice)
|
||||
}
|
||||
})*);
|
||||
}
|
||||
|
||||
impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
|
||||
impl_Display!(i64, u64: to_u64);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl_Display!(isize, usize: to_u32);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_Display!(isize, usize: to_u64);
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
//! An implementation of SipHash 2-4.
|
||||
|
||||
#![allow(deprecated)] // until the next snapshot for inherent wrapping ops
|
||||
|
||||
use prelude::*;
|
||||
use super::Hasher;
|
||||
|
||||
|
@ -184,6 +184,14 @@ extern "rust-intrinsic" {
|
||||
/// elements.
|
||||
pub fn size_of<T>() -> usize;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Moves a value to an uninitialized memory location.
|
||||
///
|
||||
/// Drop glue is not run on the destination.
|
||||
pub fn move_val_init<T>(dst: *mut T, src: T);
|
||||
|
||||
// SNAP d4432b3
|
||||
#[cfg(stage0)]
|
||||
/// Moves a value to an uninitialized memory location.
|
||||
///
|
||||
/// Drop glue is not run on the destination.
|
||||
@ -586,20 +594,26 @@ extern "rust-intrinsic" {
|
||||
pub fn overflowing_mul<T>(a: T, b: T) -> T;
|
||||
|
||||
/// Performs an unchecked signed division, which results in undefined behavior,
|
||||
/// in cases where y == 0, or x == int::MIN and y == -1
|
||||
/// in cases where y == 0, or x == isize::MIN and y == -1
|
||||
pub fn unchecked_sdiv<T>(x: T, y: T) -> T;
|
||||
/// Performs an unchecked unsigned division, which results in undefined behavior,
|
||||
/// in cases where y == 0
|
||||
pub fn unchecked_udiv<T>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the remainder of an unchecked signed division, which results in
|
||||
/// undefined behavior, in cases where y == 0, or x == int::MIN and y == -1
|
||||
pub fn unchecked_urem<T>(x: T, y: T) -> T;
|
||||
/// Returns the remainder of an unchecked signed division, which results in
|
||||
/// undefined behavior, in cases where y == 0
|
||||
/// undefined behavior, in cases where y == 0, or x == isize::MIN and y == -1
|
||||
pub fn unchecked_srem<T>(x: T, y: T) -> T;
|
||||
/// Returns the remainder of an unchecked unsigned division, which results in
|
||||
/// undefined behavior, in cases where y == 0
|
||||
pub fn unchecked_urem<T>(x: T, y: T) -> T;
|
||||
|
||||
/// Returns the value of the discriminant for the variant in 'v',
|
||||
/// cast to a `u64`; if `T` has no discriminant, returns 0.
|
||||
pub fn discriminant_value<T>(v: &T) -> u64;
|
||||
|
||||
/// Rust's "try catch" construct which invokes the function pointer `f` with
|
||||
/// the data pointer `data`, returning the exception payload if an exception
|
||||
/// is thrown (aka the thread panics).
|
||||
#[cfg(not(stage0))]
|
||||
pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
|
||||
}
|
||||
|
@ -2555,7 +2555,7 @@ impl<I: RandomAccessIterator, F> RandomAccessIterator for Inspect<I, F>
|
||||
#[unstable(feature = "iter_unfold")]
|
||||
#[derive(Clone)]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "has gained enough traction to retain its position \
|
||||
reason = "has not gained enough traction to retain its position \
|
||||
in the standard library")]
|
||||
#[allow(deprecated)]
|
||||
pub struct Unfold<St, F> {
|
||||
@ -2567,7 +2567,7 @@ pub struct Unfold<St, F> {
|
||||
|
||||
#[unstable(feature = "iter_unfold")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "has gained enough traction to retain its position \
|
||||
reason = "has not gained enough traction to retain its position \
|
||||
in the standard library")]
|
||||
#[allow(deprecated)]
|
||||
impl<A, St, F> Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
|
||||
@ -2655,8 +2655,8 @@ macro_rules! step_impl_signed {
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
|
||||
if *by == 0 { return None; }
|
||||
let mut diff: usize;
|
||||
let mut by_u: usize;
|
||||
let diff: usize;
|
||||
let by_u: usize;
|
||||
if *by > 0 {
|
||||
if *start >= *end {
|
||||
return Some(0);
|
||||
@ -3018,7 +3018,7 @@ type IterateState<T, F> = (F, Option<T>, bool);
|
||||
/// from a given seed value.
|
||||
#[unstable(feature = "iter_iterate")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "has gained enough traction to retain its position \
|
||||
reason = "has not gained enough traction to retain its position \
|
||||
in the standard library")]
|
||||
#[allow(deprecated)]
|
||||
pub type Iterate<T, F> = Unfold<IterateState<T, F>, fn(&mut IterateState<T, F>) -> Option<T>>;
|
||||
@ -3027,7 +3027,7 @@ pub type Iterate<T, F> = Unfold<IterateState<T, F>, fn(&mut IterateState<T, F>)
|
||||
/// repeated applications of the given function `f`.
|
||||
#[unstable(feature = "iter_iterate")]
|
||||
#[deprecated(since = "1.2.0",
|
||||
reason = "has gained enough traction to retain its position \
|
||||
reason = "has not gained enough traction to retain its position \
|
||||
in the standard library")]
|
||||
#[allow(deprecated)]
|
||||
pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
|
||||
|
@ -154,10 +154,6 @@ pub mod str;
|
||||
pub mod hash;
|
||||
pub mod fmt;
|
||||
|
||||
#[doc(primitive = "bool")]
|
||||
mod bool {
|
||||
}
|
||||
|
||||
// note: does not need to be public
|
||||
mod tuple;
|
||||
|
||||
|
@ -155,6 +155,7 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[deprecated(reason = "use `align_of` instead", since = "1.2.0")]
|
||||
pub fn min_align_of<T>() -> usize {
|
||||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
@ -170,14 +171,14 @@ pub fn min_align_of<T>() -> usize {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
|
||||
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the alignment in memory for a type.
|
||||
///
|
||||
/// This function will return the alignment, in bytes, of a type in memory. If the alignment
|
||||
/// returned is adhered to, then the type is guaranteed to function properly.
|
||||
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -189,17 +190,10 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn align_of<T>() -> usize {
|
||||
// We use the preferred alignment as the default alignment for a type. This
|
||||
// appears to be what clang migrated towards as well:
|
||||
//
|
||||
// http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20110725/044411.html
|
||||
unsafe { intrinsics::pref_align_of::<T>() }
|
||||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the alignment of the type of the value that `_val` points to.
|
||||
///
|
||||
/// This is similar to `align_of`, but function will properly handle types such as trait objects
|
||||
/// (in the future), returning the alignment for an arbitrary value at runtime.
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -210,8 +204,8 @@ pub fn align_of<T>() -> usize {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn align_of_val<T>(_val: &T) -> usize {
|
||||
align_of::<T>()
|
||||
pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
@ -371,11 +365,48 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
||||
|
||||
/// Disposes of a value.
|
||||
///
|
||||
/// This function can be used to destroy any value by allowing `drop` to take ownership of its
|
||||
/// argument.
|
||||
/// While this does call the argument's implementation of `Drop`, it will not
|
||||
/// release any borrows, as borrows are based on lexical scope.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2, 3];
|
||||
///
|
||||
/// drop(v); // explicitly drop the vector
|
||||
/// ```
|
||||
///
|
||||
/// Borrows are based on lexical scope, so this produces an error:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut v = vec![1, 2, 3];
|
||||
/// let x = &v[0];
|
||||
///
|
||||
/// drop(x); // explicitly drop the reference, but the borrow still exists
|
||||
///
|
||||
/// v.push(4); // error: cannot borrow `v` as mutable because it is also
|
||||
/// // borrowed as immutable
|
||||
/// ```
|
||||
///
|
||||
/// An inner scope is needed to fix this:
|
||||
///
|
||||
/// ```
|
||||
/// let mut v = vec![1, 2, 3];
|
||||
///
|
||||
/// {
|
||||
/// let x = &v[0];
|
||||
///
|
||||
/// drop(x); // this is now redundant, as `x` is going out of scope anyway
|
||||
/// }
|
||||
///
|
||||
/// v.push(4); // no problems
|
||||
/// ```
|
||||
///
|
||||
/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can
|
||||
/// seemingly release a borrow of one:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
@ -414,17 +445,22 @@ macro_rules! repeat_u8_as_u64 {
|
||||
//
|
||||
// And of course, 0x00 brings back the old world of zero'ing on drop.
|
||||
#[unstable(feature = "filling_drop")]
|
||||
#[allow(missing_docs)]
|
||||
pub const POST_DROP_U8: u8 = 0x1d;
|
||||
#[unstable(feature = "filling_drop")]
|
||||
#[allow(missing_docs)]
|
||||
pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
|
||||
#[unstable(feature = "filling_drop")]
|
||||
#[allow(missing_docs)]
|
||||
pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[unstable(feature = "filling_drop")]
|
||||
#[allow(missing_docs)]
|
||||
pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[unstable(feature = "filling_drop")]
|
||||
#[allow(missing_docs)]
|
||||
pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
|
||||
|
||||
/// Interprets `src` as `&U`, and then reads `src` without moving the contained
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
//! Operations and constants for 32-bits floats (`f32` type)
|
||||
|
||||
#![doc(primitive = "f32")]
|
||||
// FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353
|
||||
#![allow(overflowing_literals)]
|
||||
|
||||
@ -24,14 +23,18 @@ use num::{Float, ParseFloatError};
|
||||
use num::FpCategory as Fp;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const RADIX: u32 = 2;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MANTISSA_DIGITS: u32 = 24;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const DIGITS: u32 = 6;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const EPSILON: f32 = 1.19209290e-07_f32;
|
||||
|
||||
/// Smallest finite f32 value
|
||||
@ -45,20 +48,27 @@ pub const MIN_POSITIVE: f32 = 1.17549435e-38_f32;
|
||||
pub const MAX: f32 = 3.40282347e+38_f32;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MIN_EXP: i32 = -125;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MAX_EXP: i32 = 128;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MIN_10_EXP: i32 = -37;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MAX_10_EXP: i32 = 38;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const NAN: f32 = 0.0_f32/0.0_f32;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const INFINITY: f32 = 1.0_f32/0.0_f32;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32;
|
||||
|
||||
/// Basic mathematial constants.
|
||||
@ -215,13 +225,37 @@ impl Float for f32 {
|
||||
/// Rounds towards minus infinity.
|
||||
#[inline]
|
||||
fn floor(self) -> f32 {
|
||||
unsafe { intrinsics::floorf32(self) }
|
||||
return floorf(self);
|
||||
|
||||
// On MSVC LLVM will lower many math intrinsics to a call to the
|
||||
// corresponding function. On MSVC, however, many of these functions
|
||||
// aren't actually available as symbols to call, but rather they are all
|
||||
// `static inline` functions in header files. This means that from a C
|
||||
// perspective it's "compatible", but not so much from an ABI
|
||||
// perspective (which we're worried about).
|
||||
//
|
||||
// The inline header functions always just cast to a f64 and do their
|
||||
// operation, so we do that here as well, but only for MSVC targets.
|
||||
//
|
||||
// Note that there are many MSVC-specific float operations which
|
||||
// redirect to this comment, so `floorf` is just one case of a missing
|
||||
// function on MSVC, but there are many others elsewhere.
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
|
||||
}
|
||||
|
||||
/// Rounds towards plus infinity.
|
||||
#[inline]
|
||||
fn ceil(self) -> f32 {
|
||||
unsafe { intrinsics::ceilf32(self) }
|
||||
return ceilf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
|
||||
}
|
||||
|
||||
/// Rounds to nearest integer. Rounds half-way cases away from zero.
|
||||
@ -299,7 +333,13 @@ impl Float for f32 {
|
||||
|
||||
#[inline]
|
||||
fn powf(self, n: f32) -> f32 {
|
||||
unsafe { intrinsics::powf32(self, n) }
|
||||
return powf(self, n);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -317,7 +357,13 @@ impl Float for f32 {
|
||||
/// Returns the exponential of the number.
|
||||
#[inline]
|
||||
fn exp(self) -> f32 {
|
||||
unsafe { intrinsics::expf32(self) }
|
||||
return expf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
|
||||
}
|
||||
|
||||
/// Returns 2 raised to the power of the number.
|
||||
@ -329,7 +375,13 @@ impl Float for f32 {
|
||||
/// Returns the natural logarithm of the number.
|
||||
#[inline]
|
||||
fn ln(self) -> f32 {
|
||||
unsafe { intrinsics::logf32(self) }
|
||||
return logf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base.
|
||||
@ -345,7 +397,13 @@ impl Float for f32 {
|
||||
/// Returns the base 10 logarithm of the number.
|
||||
#[inline]
|
||||
fn log10(self) -> f32 {
|
||||
unsafe { intrinsics::log10f32(self) }
|
||||
return log10f(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
|
||||
}
|
||||
|
||||
/// Converts to degrees, assuming the number is in radians.
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
//! Operations and constants for 64-bits floats (`f64` type)
|
||||
|
||||
#![doc(primitive = "f64")]
|
||||
// FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353
|
||||
#![allow(overflowing_literals)]
|
||||
|
||||
@ -24,14 +23,18 @@ use num::FpCategory as Fp;
|
||||
use num::{Float, ParseFloatError};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const RADIX: u32 = 2;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MANTISSA_DIGITS: u32 = 53;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const DIGITS: u32 = 15;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const EPSILON: f64 = 2.2204460492503131e-16_f64;
|
||||
|
||||
/// Smallest finite f64 value
|
||||
@ -45,20 +48,27 @@ pub const MIN_POSITIVE: f64 = 2.2250738585072014e-308_f64;
|
||||
pub const MAX: f64 = 1.7976931348623157e+308_f64;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MIN_EXP: i32 = -1021;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MAX_EXP: i32 = 1024;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MIN_10_EXP: i32 = -307;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MAX_10_EXP: i32 = 308;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const NAN: f64 = 0.0_f64/0.0_f64;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const INFINITY: f64 = 1.0_f64/0.0_f64;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64;
|
||||
|
||||
/// Basic mathematial constants.
|
||||
|
@ -11,6 +11,5 @@
|
||||
//! Operations and constants for signed 16-bits integers (`i16` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i16")]
|
||||
|
||||
int_module! { i16, 16 }
|
||||
|
@ -11,6 +11,5 @@
|
||||
//! Operations and constants for signed 32-bits integers (`i32` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i32")]
|
||||
|
||||
int_module! { i32, 32 }
|
||||
|
@ -11,6 +11,5 @@
|
||||
//! Operations and constants for signed 64-bits integers (`i64` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i64")]
|
||||
|
||||
int_module! { i64, 64 }
|
||||
|
@ -11,6 +11,5 @@
|
||||
//! Operations and constants for signed 8-bits integers (`i8` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i8")]
|
||||
|
||||
int_module! { i8, 8 }
|
||||
|
@ -16,21 +16,25 @@ macro_rules! int_module { ($T:ty, $bits:expr) => (
|
||||
// calling the `mem::size_of` function.
|
||||
#[unstable(feature = "num_bits_bytes",
|
||||
reason = "may want to be an associated function")]
|
||||
#[allow(missing_docs)]
|
||||
pub const BITS : usize = $bits;
|
||||
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
|
||||
// calling the `mem::size_of` function.
|
||||
#[unstable(feature = "num_bits_bytes",
|
||||
reason = "may want to be an associated function")]
|
||||
#[allow(missing_docs)]
|
||||
pub const BYTES : usize = ($bits / 8);
|
||||
|
||||
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
|
||||
// calling the `Bounded::min_value` function.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MIN: $T = (-1 as $T) << (BITS - 1);
|
||||
// FIXME(#9837): Compute MIN like this so the high bits that shouldn't exist are 0.
|
||||
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
|
||||
// calling the `Bounded::max_value` function.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_docs)]
|
||||
pub const MAX: $T = !MIN;
|
||||
|
||||
) }
|
||||
|
@ -11,7 +11,6 @@
|
||||
//! Operations and constants for pointer-sized signed integers (`isize` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "isize")]
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
int_module! { isize, 32 }
|
||||
|
@ -24,6 +24,7 @@ use mem::size_of;
|
||||
use option::Option::{self, Some, None};
|
||||
use result::Result::{self, Ok, Err};
|
||||
use str::{FromStr, StrExt};
|
||||
use slice::SliceExt;
|
||||
|
||||
/// Provides intentionally-wrapped arithmetic on `T`.
|
||||
///
|
||||
@ -459,7 +460,7 @@ macro_rules! int_impl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapping (modular) division. Computes `floor(self / other)`,
|
||||
/// Wrapping (modular) division. Computes `self / other`,
|
||||
/// wrapping around at the boundary of the type.
|
||||
///
|
||||
/// The only case where such wrapping can occur is when one
|
||||
@ -467,7 +468,7 @@ macro_rules! int_impl {
|
||||
/// negative minimal value for the type); this is equivalent
|
||||
/// to `-MIN`, a positive value that is too large to represent
|
||||
/// in the type. In such a case, this function returns `MIN`
|
||||
/// itself..
|
||||
/// itself.
|
||||
#[stable(feature = "num_wrapping", since = "1.2.0")]
|
||||
#[inline(always)]
|
||||
pub fn wrapping_div(self, rhs: Self) -> Self {
|
||||
@ -668,10 +669,12 @@ macro_rules! uint_impl {
|
||||
$mul_with_overflow:path) => {
|
||||
/// Returns the smallest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn min_value() -> Self { 0 }
|
||||
|
||||
/// Returns the largest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn max_value() -> Self { !0 }
|
||||
|
||||
/// Converts a string slice in a given base to an integer.
|
||||
@ -1029,7 +1032,7 @@ macro_rules! uint_impl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapping (modular) division. Computes `floor(self / other)`,
|
||||
/// Wrapping (modular) division. Computes `self / other`,
|
||||
/// wrapping around at the boundary of the type.
|
||||
///
|
||||
/// The only case where such wrapping can occur is when one
|
||||
@ -1037,7 +1040,7 @@ macro_rules! uint_impl {
|
||||
/// negative minimal value for the type); this is equivalent
|
||||
/// to `-MIN`, a positive value that is too large to represent
|
||||
/// in the type. In such a case, this function returns `MIN`
|
||||
/// itself..
|
||||
/// itself.
|
||||
#[stable(feature = "num_wrapping", since = "1.2.0")]
|
||||
#[inline(always)]
|
||||
pub fn wrapping_div(self, rhs: Self) -> Self {
|
||||
@ -1124,7 +1127,7 @@ macro_rules! uint_impl {
|
||||
acc
|
||||
}
|
||||
|
||||
/// Returns `true` iff `self == 2^k` for some `k`.
|
||||
/// Returns `true` if and only if `self == 2^k` for some `k`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn is_power_of_two(self) -> bool {
|
||||
@ -1446,19 +1449,30 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
|
||||
-> Result<T, ParseIntError> {
|
||||
use self::IntErrorKind::*;
|
||||
use self::ParseIntError as PIE;
|
||||
|
||||
assert!(radix >= 2 && radix <= 36,
|
||||
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
|
||||
radix);
|
||||
|
||||
if src.is_empty() {
|
||||
return Err(PIE { kind: Empty });
|
||||
}
|
||||
|
||||
let is_signed_ty = T::from_u32(0) > T::min_value();
|
||||
|
||||
match src.slice_shift_char() {
|
||||
Some(('-', "")) => Err(PIE { kind: Empty }),
|
||||
Some(('-', src)) if is_signed_ty => {
|
||||
// all valid digits are ascii, so we will just iterate over the utf8 bytes
|
||||
// and cast them to chars. .to_digit() will safely return None for anything
|
||||
// other than a valid ascii digit for a the given radix, including the first-byte
|
||||
// of multi-byte sequences
|
||||
let src = src.as_bytes();
|
||||
|
||||
match (src[0], &src[1..]) {
|
||||
(b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }),
|
||||
(b'-', digits) if is_signed_ty => {
|
||||
// The number is negative
|
||||
let mut result = T::from_u32(0);
|
||||
for c in src.chars() {
|
||||
let x = match c.to_digit(radix) {
|
||||
for &c in digits {
|
||||
let x = match (c as char).to_digit(radix) {
|
||||
Some(x) => x,
|
||||
None => return Err(PIE { kind: InvalidDigit }),
|
||||
};
|
||||
@ -1473,11 +1487,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
|
||||
}
|
||||
Ok(result)
|
||||
},
|
||||
Some((_, _)) => {
|
||||
(c, digits) => {
|
||||
// The number is signed
|
||||
let mut result = T::from_u32(0);
|
||||
for c in src.chars() {
|
||||
let x = match c.to_digit(radix) {
|
||||
let mut result = match (c as char).to_digit(radix) {
|
||||
Some(x) => T::from_u32(x),
|
||||
None => return Err(PIE { kind: InvalidDigit }),
|
||||
};
|
||||
for &c in digits {
|
||||
let x = match (c as char).to_digit(radix) {
|
||||
Some(x) => x,
|
||||
None => return Err(PIE { kind: InvalidDigit }),
|
||||
};
|
||||
@ -1491,8 +1508,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
|
||||
};
|
||||
}
|
||||
Ok(result)
|
||||
},
|
||||
None => Err(ParseIntError { kind: Empty }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,5 @@
|
||||
//! Operations and constants for unsigned 16-bits integers (`u16` type)
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u16")]
|
||||
|
||||
uint_module! { u16, i16, 16 }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user