diff --git a/.gitignore b/.gitignore index 5d5da135a8272..572111bf96158 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.exe *.fn *.html +*.kdev4 *.ky *.ll *.llvm diff --git a/.mailmap b/.mailmap index ea107e0abd895..c1a605bd94c9d 100644 --- a/.mailmap +++ b/.mailmap @@ -8,12 +8,13 @@ Aaron Todd Abhishek Chanda Abhishek Chanda Ahmed Charles +Aydin Kim aydin.kim Alex Lyon Alex Rønne Petersen Andreas Gal Andrew Poelstra Anton Löfgren -Ariel Ben-Yehuda +Ariel Ben-Yehuda arielb1 Austin Seipp Ben Alpert Benjamin Jackman @@ -38,6 +39,7 @@ Eduardo Bautista Eduardo Bautista <=> Elliott Slaughter Elly Fong-Jones +Emily Dunham edunham Eric Holk Eric Holk Eric Holmes @@ -45,6 +47,7 @@ Eric Reed Erick Tryzelaar Evgeny Sologubov Falco Hirschenberger +Felix S. Klock II Felix S Klock II Gareth Daniel Smith Georges Dubus Graham Fawcett @@ -64,6 +67,7 @@ Jihyun Yu jihyun Jihyun Yu Johann Hofmann Johann Johann Hofmann John Clements +John Hodge John Hodge Jorge Aparicio Jonathan Bailey Junyoung Cho @@ -80,20 +84,24 @@ Luqman Aden Luke Metz Makoto Nakashima Makoto Nakashima gifnksm +Markus Westerlind Markus Margaret Meyerhofer Mark Sinclair Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> +Matej Lach Matej Ľach Matt Brubeck Matthew Auld Matthew McPherrin Matthijs Hofstra Michael Williams -Michael Woerister -Michael Woerister +Michael Woerister Michael Woerister Neil Pankey Nicholas Mazzuca Nicholas +Oliver Schneider Oliver 'ker' Schneider Ožbolt Menegatti gareins +Paul Faria Paul Faria Peer Aramillo Irizar parir +Peter Elmers Philipp Brüschweiler Philipp Brüschweiler Pradeep Kumar @@ -105,6 +113,7 @@ Robert Foss robertfoss Robert Gawdzik Robert Gawdzik ☢ Robert Millar Ryan Scheel +Sean Gillespie swgillespie Seonghyun Kim Simon Barber-Dueck Simon BD Simon Sapin @@ -114,7 +123,9 @@ Steven Stewart-Gallus Tamir Duberstein Tim Chevalier Torsten Weber +Vadim Petrochenkov petrochenkov William Ting +Xuefeng Wu Xuefeng Wu XuefengWu Youngsoo Son Zack Corr Zack Slayton diff --git a/.travis.yml b/.travis.yml index 29d287bfb4849..dc955bc2f2be2 100644 --- a/.travis.yml +++ b/.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/ # diff --git a/AUTHORS.txt b/AUTHORS.txt index fddfeca4b7e75..60e1a34aecb4d 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -22,11 +22,13 @@ Aidan Cully Aidan Hobson Sayers A.J. Gardner Akos Kiss +Akshay Chiwhane Alan Andrade Alan Cutter Alan Williams Aleksander Balicki Aleksandr Koshlo +Alexander Artemenko Alexander Bliskovsky Alexander Campbell Alexander Chernyakhovsky @@ -44,6 +46,7 @@ Alexis Beingessner Alex Lyon Alex Quach Alex Rønne Petersen +Alex Stokes Alex Whitney Alfie John Alisdair Owens @@ -66,8 +69,10 @@ Andrew Barchuk Andrew Cann Andrew Chin Andrew Dunham +Andrew Foote Andrew Gallant Andrew Hobden +Andrew Kensler Andrew Paseltiner Andrew Poelstra Andrew Seidl @@ -93,19 +98,21 @@ Ashok Gautham Augusto Hack auREAX Austin Bonander +Austin Hellyer Austin King Austin Seipp Avdi Grimm awlnx Axel Viala -aydin.kim Aydin Kim bachm Barosl Lee bcoopers Ben Alpert +benaryorg Ben Ashford Ben Blum +ben fleis Ben Foppa Ben Gamari Ben Gesoff @@ -128,6 +135,7 @@ Birunthan Mohanathas Björn Steinbrink blake2-ppc bluss +bluss Boris Egorov bors Bouke van der Bijl @@ -149,6 +157,7 @@ Brian J Brennan Brian J. Burg Brian Koropoff Brian Leibig +Brian Quinlan Bruno de Oliveira Abinader Bryan Dunsmore Byron Williams @@ -172,6 +181,7 @@ Ches Martin chitra Chloe <5paceToast@users.noreply.github.com> Chris Double +Chris Hellmuth Chris Morgan Chris Nixon Chris Peterson @@ -179,14 +189,17 @@ Chris Pressey Chris Sainty Chris Shea Chris Thorn +Christian Stadelmann Christoph Burgdorf Christopher Bergqvist Christopher Chambers Christopher Kendell Chris Wong chromatic +Chuck Bassett Chuck Ries Clark Gaebel +clatour Clifford Caoile Clinton Ryan Cody P Schafer @@ -201,10 +214,12 @@ Conrad Kleinespel Corey Farwell Corey Ford Corey Richardson +Cornel Punga crhino Cristian Kubis Cristi Burcă critiqjo +Cruz Julian Bishop Damian Gryski Damien Grassart Damien Radtke @@ -240,6 +255,7 @@ Darrell Hamilton Dave Herman Dave Hodder Dave Huseby +David Campbell David Creswick David Forsythe David Halperin @@ -251,7 +267,9 @@ David Rajchenbach-Teller David Reid David Renshaw David Ross +David Stygstra David Vazgenovich Shakaryan +David Voit Davis Silverman defuz Denis Defreyne @@ -271,6 +289,7 @@ Dirk Leifeld Div Shekhar diwic DJUrsus +dmgawel Dmitry Ermolov Dmitry Promsky Dmitry Vasiliev @@ -290,6 +309,7 @@ Dylan Braithwaite Dylan Ede Dzmitry Malyshau Earl St Sauver +econoplas Eduard Bopp Eduard Burtescu Eduardo Bautista @@ -297,6 +317,7 @@ Edward Wang Edward Z. Yang Ehsanul Hoque Elantsev Serj +Eli Friedman eliovir Elliott Slaughter Elly Fong-Jones @@ -304,6 +325,8 @@ elszben emanueLczirai Emanuel Rylke Emeliov Dmitrii +Emilio Cobos Álvarez +Emily Dunham Eric Allen Eric Biggers Eric Holk @@ -314,7 +337,9 @@ Erick Tryzelaar Eric Martin Eric Platon Eric Reed +Eric Ye Erik Lyon +Erik Michaels-Ober Erik Price Erik Rose Erwan @@ -344,10 +369,12 @@ Florian Wilkens Florian Zeitz fort Francisco Souza +frankamp Franklin Chen Franziska Hinkelmann free-Runner FuGangqiang +funkill g3xzh Gábor Horváth Gábor Lehel @@ -381,6 +408,7 @@ Greg Chapple Grigoriy Guillaume Gomez Guillaume Pinot +Gulshan Singh Gyorgy Andrasek Haitao Li Hajime Morrita @@ -419,6 +447,7 @@ Ivano Coppola Ivan Petkov Ivan Radanov Ivanov Ivan Ukhov +Iven Hsu Jack Heizer Jack Moffitt Jacob Edelman @@ -428,6 +457,7 @@ Jacob Parker Jaemin Moon Jag Talon Jake Goulding +Jake Hickey Jake Kaufman Jake Kerr Jake Scott @@ -439,7 +469,7 @@ James Hurst James Lal James Laverack jamesluke -James Miller +James Miller James Perry James Rowe James Sanders @@ -479,11 +509,13 @@ Jelte Fennema Jens Nockert Jeong YunWon Jeremy Letang +Jeremy Schlatter Jesse Jones Jesse Luehrs Jesse Ray Jesse Ruderman Jessy Diamond Exum +Jexell Jihyeok Seo Jihyun Yu Jim Apple @@ -504,6 +536,7 @@ Johannes Löthberg Johannes Muenzel Johannes Oertel Johann Hofmann +Johann Tuffe John Albietz John Barker John Clements @@ -519,6 +552,7 @@ John Simon John Talling John Van Enk John Zhang +joliv Jonas Hietala Jonathan Bailey Jonathan Boyett @@ -545,6 +579,7 @@ Josh Matthews Josh Stone Josh Triplett Joshua Clark +Joshua Landau Joshua Wise Joshua Yanovski JP-Ellis @@ -586,6 +621,7 @@ KokaKiwi korenchkin Kostas Karachalios Krzysztof Drewniak +Kubilay Kocak kulakowski kwantam Kyeongwoon Lee @@ -601,6 +637,7 @@ Lee Jeffery Lee Wondong LemmingAvalanche Lennart Kudling +Leo Correa Leonids Maslovs Leo Testard leunggamciu @@ -610,6 +647,7 @@ Lindsey Kuper Lionel Flandrin Logan Chien Loïc Damien +Lorenz lpy Luca Bruno lucy @@ -629,16 +667,21 @@ maikklein Makoto Nakashima Manish Goregaokar Manuel Hoffmann +marcell +Marcel Müller Marcel Rodrigues +Marcus Klaas Margaret Meyerhofer Marijn Haverbeke Marin Atanasov Nikolov +Mário Feroldi Mark Lacey <641@rudkx.com> Mark Mossberg Mark Rowe Mark Sinclair Markus Siemens Markus Unterwaditzer +Markus Westerlind Mark Vian Martin DeMello Martin Olsson @@ -648,6 +691,7 @@ Marvin Löbel masklinn Matej Lach Mateusz Czapliński +Mathieu David Mathieu Poumeyrol Mathieu Rochette Mathijs van de Nes @@ -655,6 +699,7 @@ Matt Brubeck Matt Carberry Matt Coffin Matt Cox +Matthew Astley Matthew Auld Matthew Iselin Matthew McPherrin @@ -670,6 +715,7 @@ Mátyás Mustoha Maxime Quandalle Maximilian Haack Maxim Kolganov +Max Jacobson Max Penet Maya Nitu mchaput @@ -685,7 +731,9 @@ Michael Darakananda Michael Fairley Michael Gehring Michael Kainer +Michael Layzell Michael Letterle +Michael Macias Michael Matuzak Michael Neumann Michael Pankov @@ -715,6 +763,7 @@ Mike Sampson Mikhail Zabaluev Mikko Perttunen mitchmindtree +Mohammed Attia moonglum mrec mr.Shu @@ -727,6 +776,7 @@ nathan dotz Nathan Froyd Nathaniel Herman Nathaniel Theis +Nathan Long Nathan Stoddard Nathan Typanski Nathan Wilson @@ -739,6 +789,7 @@ Nicholas Bishop Nicholas Mazzuca Nick Cameron Nick Desaulniers +Nick Fitzgerald Nick Hamann Nick Howell Nick Platt @@ -750,6 +801,7 @@ Nif Ward Nikita Pekin Niklas Koep Niko Matsakis +Nils Liberg Nils Winter noam Noam Yorav-Raphael @@ -760,10 +812,13 @@ nsf nwin Oak OGINO Masanori +OlegTsyba +Oliver Schneider Oliver Schneider Olivier Saut olivren Olle Jonsson +olombard Or Brostovski Oren Hazi Or Neeman @@ -776,6 +831,7 @@ P1start Pablo Brasero Palmer Cox Paolo Falabella +Parker Moore Pascal Hertleif Patrick Reisert Patrick Walton @@ -787,6 +843,7 @@ Paul Collier Paul Collins Paul Crowley Paul Faria +Paul Oliver Paul Osborne Paul Quint Paul Stansifer @@ -795,9 +852,10 @@ Pavel Panchekha Pawel Olzacki Pedro Larroy Peer Aramillo Irizar +peferron Pete Hunt Peter Atashian -Peter Elmers +Peter Elmers Peter Hull Peter Marheine Peter Minten @@ -839,6 +897,8 @@ Ray Clanan ray glover reedlepee Reilly Watson +Rein Henrichs +Rémi Audebert Remi Rampin Renato Alves Renato Riccieri Santos Zannon @@ -876,15 +936,18 @@ Roy Frostig Rüdiger Sonderfeld rundrop1 Russell Johnston +Russell McClellan Ruud van Asseldonk Ryan Levick Ryan Mulligan Ryan Prichard Ryan Riginding Ryan Scheel +Ryman らいどっと Sae-bom Kim Salem Talha +saml Samuel Chase Samuel Neves Sander Mathijs van Veen @@ -895,7 +958,7 @@ Santiago Rodriguez Saurabh Anand Scott Jenkins Scott Lawrence -Scott Olson +Scott Olson Sean Bowe Sean Chalmers Sean Collins @@ -932,6 +995,7 @@ Simon Kern Simon Persson Simon Sapin Simon Wollwage +simplex Sindre Johansen sinkuu Skyler @@ -945,6 +1009,7 @@ Stefan Bucur Stefan Plantikow Stepan Koltsov Sterling Greene +Steve Gury Steve Klabnik Steven Allen Steven Crockett @@ -952,9 +1017,11 @@ Steven De Coeyer Steven Fackler Steven Sheldon Steven Stewart-Gallus +Steven Walter Strahinja Val Markovic Stuart Pernsteiner Subhash Bhushan +sumito3478 Swaroop C H Sylvestre Ledru Tamir Duberstein @@ -975,6 +1042,7 @@ Thomas Backman Thomas Bracht Laumann Jespersen Thomas Daede Thomas Jespersen +Thomas Karpiniec Tiago Nobrega Tibor Benke Till Hoeppner @@ -986,6 +1054,7 @@ Tim Kuehn Timon Rapp Timothée Ravier Tim Parenti +Tim Ringenbach Tim Taubert tinaun Tincan @@ -1046,11 +1115,15 @@ Volker Mische Wade Mealing Wangshan Lu WebeWizard +webmobster Wei-Ming Yang Wendell Smith Wesley Wiser whataloadofwhat wickerwaka +Wilfred Hughes +Will Andrews +Will Engler Will Hipschman William Ting Willson Mock @@ -1058,12 +1131,15 @@ Will Wojciech Ogrodowczyk wonyong kim xales +Xuefeng Wu +XuefengWu Xuefeng Wu Xue Fuqiao Yasuhiro Fujii YawarRaza7349 Yazhong Liu Yehuda Katz +Yongqian Li York Xiang Young-il Choi Youngmin Yoo @@ -1071,6 +1147,7 @@ Youngsoo Son Young Wu Yuri Albuquerque Yuri Kunde Schlesner +Z1 Zach Kamsler Zach Pomerantz Zack Corr diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0bcb3219858c9..22a23de070780 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/Makefile.in b/Makefile.in index d3bb5a541a470..8968fabf1b4b3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/README.md b/README.md index c8f00ba1acd8d..9e54704a5ebad 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/RELEASES.md b/RELEASES.md index 9932684a34cc4..db1c7380a788b 100644 --- a/RELEASES.md +++ b/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 diff --git a/configure b/configure index d72fe0759838d..542d829e2cd63 100755 --- a/configure +++ b/configure @@ -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) - - 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" - ;; + CFG_CLANG_REPORTED_VERSION=$($CFG_CC --version | grep version) + + 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 diff --git a/mk/cfg/i686-pc-windows-msvc.mk b/mk/cfg/i686-pc-windows-msvc.mk new file mode 100644 index 0000000000000..bb1280688a716 --- /dev/null +++ b/mk/cfg/i686-pc-windows-msvc.mk @@ -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 diff --git a/mk/cfg/i686-unknown-freebsd.mk b/mk/cfg/i686-unknown-freebsd.mk new file mode 100644 index 0000000000000..0ac0ca98a2f1e --- /dev/null +++ b/mk/cfg/i686-unknown-freebsd.mk @@ -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 diff --git a/mk/cfg/x86_64-pc-windows-msvc.mk b/mk/cfg/x86_64-pc-windows-msvc.mk index 69a26c03fb664..6f12836f05624 100644 --- a/mk/cfg/x86_64-pc-windows-msvc.mk +++ b/mk/cfg/x86_64-pc-windows-msvc.mk @@ -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. diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk new file mode 100644 index 0000000000000..401b0fb7ab008 --- /dev/null +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -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 diff --git a/mk/main.mk b/mk/main.mk index 39261191fb74f..964ae626d0c8d 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -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), diff --git a/mk/platform.mk b/mk/platform.mk index 8a5e58c46f676..60fe22cb32ee6 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -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)))) + diff --git a/mk/rt.mk b/mk/rt.mk index 777a2a0fd3b4b..69277e774e43b 100644 --- a/mk/rt.mk +++ b/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) diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk index 50d993701421e..6adffda7d1b32 100644 --- a/mk/rustllvm.mk +++ b/mk/rustllvm.mk @@ -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))) \ diff --git a/mk/target.mk b/mk/target.mk index 3c274dc4fd5f2..c2de9af39c764 100644 --- a/mk/target.mk +++ b/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)))))) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 92a94d23f0842..36c676391019b 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -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 ) -> 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)); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5a076b8437e26..5b62f29b82423 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -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) -> Option { split_maybe_args(options).into_iter() .filter(|x| !options_to_remove.contains(x)) .collect::>() - .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); } diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 184d62db45114..13d6c029ff584 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -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"), diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index e887ed0cc5297..5e99876f5dab8 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -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() { diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index 0374166405c62..dc80ec4399131 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -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. diff --git a/src/doc/index.md b/src/doc/index.md index fba919b711586..c1f9ea6b3b003 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -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 diff --git a/src/doc/reference.md b/src/doc/reference.md index a3e13acccae28..9528871a77491 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -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) 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 = 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 = 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` 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. - 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`; + For example, `128` is coerced to have type `i8` in the following: -* instantiations of struct or variant fields. + ```rust + fn bar(_: i8) { } - Assume we have a `struct - Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to - have type `U`. + fn main() { + bar(128); + } + ``` -* function results (either the final line of a block if it is not semicolon -terminated or any expression in a `return` statement). +* Instantiations of struct or variant fields - In `fn foo() -> U { e }`, `e` is coerced to to have type `U`. + 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`. 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`. * 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 diff --git a/src/doc/rust.css b/src/doc/rust.css index cd158283180a2..6204f38a37753 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -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; } diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index ca3381ffba465..85f0019276eef 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -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) diff --git a/src/doc/trpl/academic-research.md b/src/doc/trpl/academic-research.md index dec46de650133..e317f67934498 100644 --- a/src/doc/trpl/academic-research.md +++ b/src/doc/trpl/academic-research.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) diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md new file mode 100644 index 0000000000000..6d37043354282 --- /dev/null +++ b/src/doc/trpl/advanced-linking.md @@ -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 '
' 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. diff --git a/src/doc/trpl/choosing-your-guarantees.md b/src/doc/trpl/choosing-your-guarantees.md new file mode 100644 index 0000000000000..db28ce6f42861 --- /dev/null +++ b/src/doc/trpl/choosing-your-guarantees.md @@ -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` + +[`Box`][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`, but should be avoided in +safe code. + +## `Rc` + +This is the first wrapper we will cover that has a runtime cost. + +[`Rc`][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` 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`. 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` +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` is a single allocation, though it will allocate two extra words (i.e. +two `usize` values) as compared to a regular `Box` (for "strong" and "weak" refcounts). + +`Rc` 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`. + +[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`). + +[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` + +[`Cell`][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`, however if you are using it to wrap larger (`Copy`) +structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is +otherwise a full copy of the struct. + + +## `RefCell` + +[`RefCell`][refcell] also provides interior mutability, but isn't restricted to `Copy` types. + +Instead, it has a runtime cost. `RefCell` 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` and +`RefCell`, 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` and `Mutex`/`RWLock` + +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` + +[`Arc`][arc] is just a version of `Rc` 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>`, `Arc>`, or +`Arc>`[^4] (`UnsafeCell` 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>` actually won't compile since `UnsafeCell` isn't `Send` or `Sync`, but we can wrap it in a type and implement `Send`/`Sync` for it manually to get `Arc>` where `Wrapper` is `struct Wrapper(UnsafeCell)`. + +#### 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` and `RwLock` + +[`Mutex`][mutex] and [`RwLock`][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>>` (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>` is one such composition. `Rc` itself can't be dereferenced mutably; +because `Rc` provides sharing and shared mutability can lead to unsafe behavior, so we put +`RefCell` 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>>` or `Rc>>`. These +are both shareable, mutable vectors, but they're not the same. + +With the former, the `RefCell` is wrapping the `Vec`, so the `Vec` 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` at will. This is +similar to an `&mut Vec` 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>`, 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>` and `RefCell>`, 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. diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 7687d2a57da92..e7eb48dc42c52 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -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 diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index ccd769089d251..15c19ece48a14 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -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` diff --git a/src/doc/trpl/dining-philosophers.md b/src/doc/trpl/dining-philosophers.md index b24d50c890da4..9539cd3447cb9 100644 --- a/src/doc/trpl/dining-philosophers.md +++ b/src/doc/trpl/dining-philosophers.md @@ -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 +Judith Butler is eating. Gilles Deleuze is eating. -Gilles Deleuze is done eating. +Karl Marx is eating. Emma Goldman is eating. -Emma Goldman is done eating. Michel Foucault is eating. -Judith Butler is eating. Judith Butler is done eating. -Karl Marx is eating. +Gilles Deleuze is done eating. Karl Marx is done eating. +Emma Goldman is done eating. Michel Foucault is done eating. ``` diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 7102158383a9b..01b53a6c49d8b 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -33,8 +33,10 @@ pub fn new(value: T) -> Rc { ``` 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. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 580eaa6ca5571..8dd5a3650ef52 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -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)); } ``` diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 917d8dbe196c7..753a5a32e8a1b 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -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; diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index a599b8a855e92..1784c253f7f47 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -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 diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md index 4d9166d63bfb7..7659c4ff88dae 100644 --- a/src/doc/trpl/inline-assembly.md +++ b/src/doc/trpl/inline-assembly.md @@ -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 diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 39e8ea6cbd319..83750ec3b01ad 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -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 diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 11d651c5778e3..8e02367b921bc 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -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 diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md deleted file mode 100644 index ee5159afb8e6f..0000000000000 --- a/src/doc/trpl/link-args.md +++ /dev/null @@ -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. - diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 46af311acf315..5ddbdd6df00b0 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -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() { diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 7a1f8bf21bf34..9603eec7aca71 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -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`: + +```rust +# let some_value: Result = 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 diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index b27db2ab7bea8..d1d3063138e7e 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -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. diff --git a/src/doc/trpl/release-channels.md b/src/doc/trpl/release-channels.md index 03e65539a2042..1e203c6553ee1 100644 --- a/src/doc/trpl/release-channels.md +++ b/src/doc/trpl/release-channels.md @@ -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. diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index 759543140b576..a5a0127031ae5 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -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 } diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index 2c5f5927fd15a..ff81590cc03b9 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -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”. diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index fdb9c33a2b0b5..1b223365bd63a 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -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. + +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. -But it will let you write things that _do_ break some of the rules. Let’s go -over these three abilities in order. +Let’s go over the basic three abilities listed, in order. ## Access or update a `static mut` diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index 0f5c3c64a4b17..124ebc7d69ddc 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -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 diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index 6e667b37a9c5c..06a83c75936fe 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -55,12 +55,10 @@ 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 diff --git a/src/etc/errorck.py b/src/etc/errorck.py index 4b1b78da9fde4..48736542f20c7 100644 --- a/src/etc/errorck.py +++ b/src/etc/errorck.py @@ -23,6 +23,18 @@ errcode_map = {} error_re = re.compile("(E\d\d\d\d)") +# In the register_long_diagnostics! macro, entries look like this: +# +# EXXXX: r##" +# +# "##, +# +# 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 @@ 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 @@ else: errcode_map[errcode] = new_record + if long_diag_begin in line: + inside_long_diag = True + errors = False all_errors = [] diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 7a925fa3f3367..1cc65406b2c00 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -14,10 +14,9 @@ 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 @@ def run(args): 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") diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index 0349ccf9b6640..6d62a45c703a2 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -41,13 +41,14 @@ def scrub(b): 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" diff --git a/src/etc/unicode.py b/src/etc/unicode.py index f580127cddaf8..a740e837fdd4e 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -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 { 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): diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7bfeaec36d729..2a47fd29bd653 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -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 { unsafe impl Send for Weak { } unsafe impl Sync for Weak { } +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -154,7 +158,12 @@ impl fmt::Debug for Weak { struct ArcInner { 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 Arc { #[unstable(feature = "arc_weak", reason = "Weak pointers may not belong in this module.")] pub fn downgrade(&self) -> Weak { - // 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 Arc { 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(this: &Arc) -> usize { Arc::weak_count(this) } #[deprecated(since = "1.2.0", reason = "renamed to Arc::strong_count")] pub fn strong_count(this: &Arc) -> usize { Arc::strong_count(this) } - -/// Returns a mutable reference to the contained value if the `Arc` is unique. -/// -/// Returns `None` if the `Arc` 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(this: &mut Arc) -> 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 Clone for Arc { /// Makes a clone of the `Arc`. @@ -350,10 +330,9 @@ impl Arc { /// Make a mutable reference from the given `Arc`. /// /// 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,33 +340,140 @@ impl Arc { /// # #![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")] - #[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 + pub fn make_unique(this: &mut Arc) -> &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. // - // 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()) + // 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. - let inner = &mut **self._ptr; - &mut inner.data + unsafe { + let inner = &mut **this._ptr; + &mut inner.data + } } } +impl Arc { + /// Returns a mutable reference to the contained value if the `Arc` is unique. + /// + /// Returns `None` if the `Arc` 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")] + pub fn get_mut(this: &mut Arc) -> 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 + } + } + + /// 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(this: &mut Arc) -> Option<&mut T> { + Arc::get_mut(this) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Arc { /// Drops the `Arc`. @@ -483,9 +569,15 @@ impl Weak { // 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 Clone for Weak { /// ``` #[inline] fn clone(&self) -> Weak { - // 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 Drop for Weak { // 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); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1039756363e9f..acf2209423323 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -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(Unique); +pub struct Box(Unique); + +/// `IntermediateBox` represents uninitialized backing storage for `Box`. +/// +/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of +/// introducing a separate `IntermediateBox`; 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{ + ptr: *mut u8, + size: usize, + align: usize, + marker: marker::PhantomData<*mut T>, +} + +impl Place for IntermediateBox { + fn pointer(&mut self) -> *mut T { + unsafe { ::core::mem::transmute(self.ptr) } + } +} + +unsafe fn finalize(b: IntermediateBox) -> Box { + let p = b.ptr as *mut T; + mem::forget(b); + mem::transmute(p) +} + +fn make_place() -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + 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 BoxPlace for IntermediateBox { + fn make_place() -> IntermediateBox { make_place() } +} + +impl InPlace for IntermediateBox { + type Owner = Box; + unsafe fn finalize(self) -> Box { finalize(self) } +} + +impl Boxed for Box { + type Data = T; + type Place = IntermediateBox; + unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } +} + +impl Placer for ExchangeHeapSingleton { + type Place = IntermediateBox; + + fn make_place(self) -> IntermediateBox { + make_place() + } +} + +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr, self.size, self.align) + } + } + } +} impl Box { /// Allocates memory on the heap and then moves `x` into it. @@ -116,7 +214,7 @@ impl Box { /// 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 Box { /// # 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 Clone for Box { /// let y = x.clone(); /// ``` #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } - + fn clone(&self) -> Box { box (HEAP) {(**self).clone()} } /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index fc44ac4eac628..2ef23b26a56a7 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -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 = Box::new(Bar(17)); + let p = Box::into_raw(x); unsafe { - let x: Box = Box::new(Bar(17)); - let p = boxed::into_raw(x); assert_eq!(17, (*p).get()); (*p).set(19); let y: Box = Box::from_raw(p); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7dcf7a76da083..f66495c4057c4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -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() {} diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs new file mode 100644 index 0000000000000..9311f44d9df00 --- /dev/null +++ b/src/liballoc/raw_vec.rs @@ -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 or the MIT license +// , 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 { + ptr: Unique, + cap: usize, +} + +impl RawVec { + /// 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::() == 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::(); + + 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::(); + 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`. + 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 RawVec { + /// 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::() == 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 { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// 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::(); + + // 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::(); + + 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::(); + let align = mem::align_of::(); + + // 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 { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// 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::(); + let align = mem::align_of::(); + + // 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::(); + let align = mem::align_of::(); + + // 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 Drop for RawVec { + /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + fn drop(&mut self) { + let elem_size = mem::size_of::(); + if elem_size != 0 && self.cap != 0 && self.unsafe_no_drop_flag_needs_drop() { + let align = mem::align_of::(); + + 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"); +} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d5b6c86ef359a..d461eeea0b7eb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -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 Rc { // 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::>(), - min_align_of::>()); + align_of::>()); forget(rc); Ok(val) } @@ -496,7 +496,7 @@ impl Drop for Rc { 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 { impl !marker::Send for Weak {} impl !marker::Sync for Weak {} +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[unstable(feature = "rc_weak", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -805,7 +807,7 @@ impl Drop for Weak { // 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)) } } } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 109ad8a942c84..4d064b16ad027 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -244,7 +244,7 @@ impl<'longer_than_self> Arena<'longer_than_self> { fn alloc_copy(&self, op: F) -> &mut T where F: FnOnce() -> T { unsafe { let ptr = self.alloc_copy_inner(mem::size_of::(), - mem::min_align_of::()); + mem::align_of::()); 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::(); let (ty_ptr, ptr) = self.alloc_noncopy_inner(mem::size_of::(), - mem::min_align_of::()); + mem::align_of::()); 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 { fn calculate_size(capacity: usize) -> usize { let mut size = mem::size_of::>(); - size = round_up(size, mem::min_align_of::()); + size = round_up(size, mem::align_of::()); let elem_size = mem::size_of::(); let elems_size = elem_size.checked_mul(capacity).unwrap(); size = size.checked_add(elems_size).unwrap(); @@ -405,7 +405,7 @@ impl TypedArenaChunk { unsafe fn new(next: *mut TypedArenaChunk, capacity: usize) -> *mut TypedArenaChunk { let size = calculate_size::(capacity); - let chunk = allocate(size, mem::min_align_of::>()) + let chunk = allocate(size, mem::align_of::>()) as *mut TypedArenaChunk; if chunk.is_null() { alloc::oom() } (*chunk).next = next; @@ -431,7 +431,7 @@ impl TypedArenaChunk { let size = calculate_size::(self.capacity); let self_ptr: *mut TypedArenaChunk = self; deallocate(self_ptr as *mut u8, size, - mem::min_align_of::>()); + mem::align_of::>()); if !next.is_null() { let capacity = (*next).capacity; (*next).destroy(capacity); @@ -444,7 +444,7 @@ impl TypedArenaChunk { let this: *const TypedArenaChunk = self; unsafe { mem::transmute(round_up(this.offset(1) as usize, - mem::min_align_of::())) + mem::align_of::())) } } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 51914900fdd99..3a4cfbba65f4e 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -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(); diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index d7242b9077556..1c75636cb052d 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -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 /// diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 2d8335d373473..4d76a986700a2 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -163,12 +163,12 @@ fn test_offset_calculation() { } fn calculate_allocation_generic(capacity: usize, is_leaf: bool) -> (usize, usize) { - let (keys_size, keys_align) = (capacity * mem::size_of::(), mem::min_align_of::()); - let (vals_size, vals_align) = (capacity * mem::size_of::(), mem::min_align_of::()); + let (keys_size, keys_align) = (capacity * mem::size_of::(), mem::align_of::()); + let (vals_size, vals_align) = (capacity * mem::size_of::(), mem::align_of::()); let (edges_size, edges_align) = if is_leaf { (0, 1) } else { - ((capacity + 1) * mem::size_of::>(), mem::min_align_of::>()) + ((capacity + 1) * mem::size_of::>(), mem::align_of::>()) }; calculate_allocation( @@ -181,11 +181,11 @@ fn calculate_allocation_generic(capacity: usize, is_leaf: bool) -> (usize, fn calculate_offsets_generic(capacity: usize, is_leaf: bool) -> (usize, usize) { let keys_size = capacity * mem::size_of::(); let vals_size = capacity * mem::size_of::(); - let vals_align = mem::min_align_of::(); + let vals_align = mem::align_of::(); let edges_align = if is_leaf { 1 } else { - mem::min_align_of::>() + mem::align_of::>() }; calculate_offsets( diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 72d0ca85357a4..7df259e9b36a8 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -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 integer `N` itself is the precision. +//! +//! 2. An integer followed by dollar sign `.N$`: //! -//! The first specification, `.N`, means the integer `N` itself is the precision. +//! use format *argument* `N` (which must be a `usize`) as the precision. //! -//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision. +//! 3. An asterisk `.*`: //! -//! 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 `{:.*}`, then the `` part -//! refers to the *value* to print, and the `precision` must come in the input preceding ``. +//! `.*` 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 `{:.*}`, then the `` part refers +//! to the *value* to print, and the `precision` must come in the input preceding ``. //! //! For example, these: //! diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 8d0f57de4c595..1f94838499218 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -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 diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d49463911e66e..4378d0804df96 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -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] { /// 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 { #[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 { /// 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> SliceConcatExt for [V] { result } - fn connect(&self, sep: &T) -> Vec { + fn join(&self, sep: &T) -> Vec { 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> SliceConcatExt for [V] { } result } + + fn connect(&self, sep: &T) -> Vec { + self.join(sep) + } } /// An iterator that yields the element swaps needed to produce diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 5e8a9bca342b0..7c64dea3dc338 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -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> SliceConcatExt for [S] { type Output = String; @@ -105,7 +71,7 @@ impl> SliceConcatExt 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> SliceConcatExt 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) { 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 = "abc åäö".chars().collect(); + /// let v: Vec = "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` into a `String` without copying or allocating. + #[unstable(feature = "box_str", + reason = "recently added, matches RFC")] + pub fn into_string(self: Box) -> String { + unsafe { + let slice = mem::transmute::, Box<[u8]>>(self); + String::from_utf8_unchecked(slice.into_vec()) + } + } } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 6e37a5731b384..cc58952be600a 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -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`; + /// This is _very_ unsafe because: + /// + /// * We call `Vec::from_raw_parts` to get a `Vec`. 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`. + /// + /// Note that this will drop any excess capacity. + #[unstable(feature = "box_str", + reason = "recently added, matches RFC")] + pub fn into_boxed_slice(self) -> Box { + let slice = self.vec.into_boxed_slice(); + unsafe { mem::transmute::, Box>(slice) } + } } impl FromUtf8Error { @@ -963,6 +979,35 @@ impl ops::Index for String { } } +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut 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")] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 54528c50f1d1e..007de408efec7 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -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` 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 { - ptr: Unique, + buf: RawVec, len: usize, - cap: usize, } -unsafe impl Send for Vec { } -unsafe impl Sync for Vec { } - //////////////////////////////////////////////////////////////////////////////// // Inherent methods //////////////////////////////////////////////////////////////////////////////// @@ -177,11 +166,7 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Vec { - // 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` with the specified capacity. @@ -212,22 +197,23 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> Vec { - if mem::size_of::() == 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::()) - .expect("capacity overflow"); - let ptr = unsafe { allocate(size, mem::min_align_of::()) }; - 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` 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` + /// (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 Vec { pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec { Vec { - ptr: Unique::new(ptr), + buf: RawVec::from_raw_parts(ptr, capacity), len: length, - cap: capacity, } } @@ -299,7 +284,7 @@ impl Vec { #[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 Vec { /// ``` #[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 Vec { /// ``` #[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 Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - if mem::size_of::() == 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::(), - self.len * mem::size_of::(), - mem::min_align_of::()) 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 Vec { /// `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 Vec { 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 Vec { 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 Vec { 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 Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, value: T) { - #[cold] - #[inline(never)] - fn resize(vec: &mut Vec) { - let old_size = vec.cap * mem::size_of::(); - if old_size >= MAX_MEMORY_SIZE { panic!("capacity overflow") } - let mut size = max(old_size, 2 * mem::size_of::()) * 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::() == 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 Vec { #[unstable(feature = "append", reason = "new API, waiting for dust to settle")] pub fn append(&mut self, other: &mut Self) { - if mem::size_of::() == 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 Vec { // 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::() == mem::min_align_of::()); + assert!(mem::align_of::() == mem::align_of::()); // This `as isize` cast is safe, because the size of the elements of the // vector is not 0, and: @@ -1099,12 +1016,35 @@ impl Vec { 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 Vec { // Internal methods and functions //////////////////////////////////////////////////////////////////////////////// -impl Vec { - /// 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::() == 0 { return } - - if capacity > self.cap { - let size = capacity.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - unsafe { - let ptr = alloc_or_realloc(*self.ptr, self.cap * mem::size_of::(), 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(ptr: *mut T, old_size: usize, size: usize) -> *mut T { - if old_size == 0 { - allocate(size, mem::min_align_of::()) as *mut T - } else { - reallocate(ptr as *mut u8, old_size, size, mem::min_align_of::()) as *mut T - } -} - -#[inline] -unsafe fn dealloc(ptr: *mut T, len: usize) { - if mem::size_of::() != 0 { - deallocate(ptr as *mut u8, - len * mem::size_of::(), - mem::min_align_of::()) - } -} - #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { - 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 ops::Deref for Vec { 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 ops::Deref for Vec { impl ops::DerefMut for Vec { 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 FromIterator for Vec { 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 IntoIterator for Vec { /// } /// ``` #[inline] - fn into_iter(self) -> IntoIter { + fn into_iter(mut self) -> IntoIter { 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::() == 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 Vec { 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 Ord for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Vec { 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 { - allocation: *mut T, // the block of memory allocated for the vector - cap: usize, // the capacity of the vector + buf: RawVec, ptr: *const T, end: *const T } @@ -1746,9 +1630,9 @@ impl IntoIter { pub fn into_inner(mut self) -> Vec { 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 ExactSizeIterator for IntoIter {} impl Drop for IntoIter { 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 -//////////////////////////////////////////////////////////////////////////////// - -/// Wrapper type providing a `&Vec` 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, - 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; - - fn deref<'b>(&'b self) -> &'b Vec { - &self.x - } -} - -// Prevent the inner `Vec` 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` reference. -/// -/// # Examples -/// -/// ``` -/// # #![feature(collections)] -/// use std::vec::as_vec; -/// -/// // Let's pretend we have a function that requires `&Vec` -/// fn vec_consumer(s: &Vec) { -/// assert_eq!(s, &[1, 2, 3]); -/// } -/// -/// // Provide a `&Vec` 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 //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index edcd1008747fd..7bdc10cfb64fa 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -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 { // 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, + buf: RawVec, } #[stable(feature = "rust1", since = "1.0.0")] @@ -63,13 +65,7 @@ impl Clone for VecDeque { impl Drop for VecDeque { fn drop(&mut self) { self.clear(); - unsafe { - if mem::size_of::() != 0 { - heap::deallocate(*self.ptr as *mut u8, - self.cap * mem::size_of::(), - mem::min_align_of::()) - } - } + // RawVec handles deallocation } } @@ -80,78 +76,127 @@ impl Default for VecDeque { } impl VecDeque { + /// 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 VecDeque { @@ -167,24 +212,11 @@ impl VecDeque { // +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::()) - .expect("capacity overflow"); - - let ptr = unsafe { - if mem::size_of::() != 0 { - let ptr = heap::allocate(size, mem::min_align_of::()) 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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { 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 VecDeque { /// ``` #[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 VecDeque { } /// 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 VecDeque { /// ``` #[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); - - if mem::size_of::() != 0 { - let old = self.cap * mem::size_of::(); - let new = count.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - unsafe { - let ptr = heap::reallocate(*self.ptr as *mut u8, - old, - new, - mem::min_align_of::()) 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); + 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 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 VecDeque { /// ``` 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 VecDeque { // 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 VecDeque { debug_assert!(self.head < self.tail); } - if mem::size_of::() != 0 { - let old = self.cap * mem::size_of::(); - let new_size = target_cap * mem::size_of::(); - unsafe { - let ptr = heap::reallocate(*self.ptr as *mut u8, - old, - new_size, - mem::min_align_of::()) 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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { /// 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 VecDeque { 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 VecDeque { 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 VecDeque { 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 VecDeque { /// 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 VecDeque { // 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 VecDeque { 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 VecDeque { // [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 VecDeque { 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 VecDeque { // 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 VecDeque { // 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 VecDeque { } // 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 VecDeque { /// assert_eq!(Some(&15), buf.get(2)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, i: usize) -> Option { - if self.is_empty() || self.len() <= i { + pub fn remove(&mut self, index: usize) -> Option { + if self.is_empty() || self.len() <= index { return None; } @@ -1173,14 +1154,14 @@ impl VecDeque { // 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 VecDeque { // [. . . . 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 VecDeque { // [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 VecDeque { // 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 VecDeque { 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 VecDeque { 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 VecDeque { 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 VecDeque { } impl VecDeque { - /// 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 Index for VecDeque { 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 IndexMut for VecDeque { #[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); } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 20a3625fe5add..d161dc7a287f9 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -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; diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index e1c4e05e192c7..c0ab11380d9f6 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -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::::new(); - a.tail(); -} - -#[test] -#[should_panic] -fn test_tail_mut_empty() { - let mut a = Vec::::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::::new(); - a.init(); -} - -#[test] -#[should_panic] -fn test_init_mut_empty() { - let mut a = Vec::::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; 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> = (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![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::() % (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::() % l); diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 3f32136bc2639..5419c43ba096b 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -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 in the first place is through a String, so just + // test that we can round-trip between Box 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); }) } diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 257caca4016df..80283741cccdf 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -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(|| { diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index df63fbc62fcf4..7b340dc5be42a 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -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::>() == size_of::() * 3); diff --git a/src/libcore/any.rs b/src/libcore/any.rs index f0c77ae866d59..e7b39c11f4c1b 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -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` adds the `move` method, which will unwrap a `Box` from the //! object. See the extension traits (`*Ext`) for the full details. diff --git a/src/libcore/array.rs b/src/libcore/array.rs index a9b240de30bef..cfe22b8917874 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -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")] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 1b8ee8db5f47a..c6434e71957ae 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -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 AtomicPtr { 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 AtomicPtr { /// ``` #[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(dst: *mut T, val: T, order:Ordering) { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), @@ -965,7 +965,6 @@ unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_swap(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(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(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(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(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(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_compare_and_swap(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(dst: *mut T, old:T, new:T, order: Ordering) } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_and(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(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_nand(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(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_or(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(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_xor(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 fmt::Debug for AtomicPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + } +} diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 37f37654c1fee..2c4ebeafc0bc5 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -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` and `Arc`, provide containers that can be +//! Many shared smart pointer types, including `Rc` and `Arc`, 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` inside shared pointer types to reintroduce //! mutability: @@ -65,8 +65,8 @@ //! ``` //! //! Note that this example uses `Rc` and not `Arc`. `RefCell`s are for single-threaded -//! scenarios. Consider using `Mutex` if you need shared mutability in a multi-threaded -//! situation. +//! scenarios. Consider using `RwLock` or `Mutex` if you need shared mutability in a +//! multi-threaded situation. //! //! ## Implementation details of logically-immutable methods //! diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 12aa06667a1dd..c6d0e97a0cd00 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -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 { 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 { 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; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 0269499ad5414..52ed29c1b61f4 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -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 { /// This method returns an `Ordering` between `self` and `other`. diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 32d6aa19c6456..22f0215f0aded 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -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> { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index cbbb186af7609..29a2f76ef290b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -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,)* } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index fc49f87d10769..8141916dd60fc 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -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 + Rem + Sub + 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); diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index a92b72e0f00fa..d26e9ab707205 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -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; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 455928077da46..1d466895f2cfb 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -184,6 +184,14 @@ extern "rust-intrinsic" { /// elements. pub fn size_of() -> 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(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(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(x: T, y: T) -> T; /// Performs an unchecked unsigned division, which results in undefined behavior, /// in cases where y == 0 pub fn unchecked_udiv(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(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(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(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(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; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3026f91e853ee..415326a8a616e 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2555,7 +2555,7 @@ impl RandomAccessIterator for Inspect #[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 { @@ -2567,7 +2567,7 @@ pub struct Unfold { #[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 Unfold where F: FnMut(&mut St) -> Option { @@ -2655,8 +2655,8 @@ macro_rules! step_impl_signed { #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t, by: &$t) -> Option { 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 = (F, Option, 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 = Unfold, fn(&mut IterateState) -> Option>; @@ -3027,7 +3027,7 @@ pub type Iterate = Unfold, fn(&mut IterateState) /// 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(seed: T, f: F) -> Iterate where diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 030d2a33f8f65..ef2a33c37dd30 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -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; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 15e7cdbde408d..271d83201b1a5 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -155,6 +155,7 @@ pub fn size_of_val(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() -> usize { unsafe { intrinsics::min_align_of::() } } @@ -170,14 +171,14 @@ pub fn min_align_of() -> 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(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(val: &T) -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn align_of() -> 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::() } + unsafe { intrinsics::min_align_of::() } } -/// 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() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of_val(_val: &T) -> usize { - align_of::() +pub fn align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } } /// Creates a value initialized to zero. @@ -371,11 +365,48 @@ pub fn replace(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 diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index aade9061657b7..6b4424093b407 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -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. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 7c9e846af9b10..fa7aa2ab5ce8c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -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. diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 5ea60d0d96d29..dacb4ebcdfa3a 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -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 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 7d9faa998c12e..250d66de70b34 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -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 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 5a70911387b9b..5ed21d7246cd0 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -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 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 1d7d78ffa6c23..0394c12d5c457 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -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 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index efc9123880978..cb9bffca84256 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -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; ) } diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 2cdfe03eafe7f..066cb10cce265 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -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 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97b4f77675533..bfbb2ded0782d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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(src: &str, radix: u32) -> Result { 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(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(src: &str, radix: u32) }; } Ok(result) - }, - None => Err(ParseIntError { kind: Empty }), + } } } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 21635799a77a2..ecf799448483c 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -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 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 7d520770503d4..b0682b55ac05d 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index f10822077dc75..dbc6a64a905d2 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 3d6922b07b194..bf9347ca62c92 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 0719d7c17cc4e..b31d6a73a7fa9 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -14,14 +14,18 @@ macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => ( #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BITS : usize = $bits; #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BYTES : usize = ($bits / 8); #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN: $T = 0 as $T; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX: $T = !0 as $T; ) } diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 6fd23425e4d89..67e3c954ab695 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -11,6 +11,5 @@ //! Operations and constants for pointer-sized unsigned integers (`usize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 748ed29e3a306..2e3b34af51382 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -119,6 +119,16 @@ macro_rules! wrapping_impl { } } + #[stable(feature = "wrapping_div", since = "1.3.0")] + impl Div for Wrapping<$t> { + type Output = Wrapping<$t>; + + #[inline(always)] + fn div(self, other: Wrapping<$t>) -> Wrapping<$t> { + Wrapping(self.0.wrapping_div(other.0)) + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Not for Wrapping<$t> { type Output = Wrapping<$t>; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 48b1cbeef4fdd..c1cf2230ac476 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -351,8 +351,10 @@ pub trait Div { fn div(self, rhs: RHS) -> Self::Output; } -macro_rules! div_impl { +macro_rules! div_impl_integer { ($($t:ty)*) => ($( + /// This operation rounds towards zero, truncating any + /// fractional part of the exact result. #[stable(feature = "rust1", since = "1.0.0")] impl Div for $t { type Output = $t; @@ -365,7 +367,23 @@ macro_rules! div_impl { )*) } -div_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +div_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + +macro_rules! div_impl_float { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Div for $t { + type Output = $t; + + #[inline] + fn div(self, other: $t) -> $t { self / other } + } + + forward_ref_binop! { impl Div, div for $t, $t } + )*) +} + +div_impl_float! { f32 f64 } /// The `Rem` trait is used to specify the functionality of `%`. /// @@ -407,6 +425,8 @@ pub trait Rem { macro_rules! rem_impl { ($($t:ty)*) => ($( + /// This operation satisfies `n % d == n - (n / d) * d`. The + /// result has the same sign as the left operand. #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { type Output = $t; @@ -419,26 +439,40 @@ macro_rules! rem_impl { )*) } -macro_rules! rem_float_impl { - ($t:ty, $fmod:ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { - type Output = $t; +rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } - #[inline] - fn rem(self, other: $t) -> $t { - extern { fn $fmod(a: $t, b: $t) -> $t; } - unsafe { $fmod(self, other) } - } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f32 { + type Output = f32; + + // see notes in `core::f32::Float::floor` + #[inline] + #[cfg(target_env = "msvc")] + fn rem(self, other: f32) -> f32 { + (self as f64).rem(other as f64) as f32 + } - forward_ref_binop! { impl Rem, rem for $t, $t } + #[inline] + #[cfg(not(target_env = "msvc"))] + fn rem(self, other: f32) -> f32 { + extern { fn fmodf(a: f32, b: f32) -> f32; } + unsafe { fmodf(self, other) } } } -rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } -rem_float_impl! { f32, fmodf } -rem_float_impl! { f64, fmod } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f64 { + type Output = f64; + + #[inline] + fn rem(self, other: f64) -> f64 { + extern { fn fmod(a: f64, b: f64) -> f64; } + unsafe { fmod(self, other) } + } +} + +forward_ref_binop! { impl Rem, rem for f64, f64 } +forward_ref_binop! { impl Rem, rem for f32, f32 } /// The `Neg` trait is used to specify the functionality of unary `-`. /// @@ -483,7 +517,6 @@ pub trait Neg { macro_rules! neg_impl_core { ($id:ident => $body:expr, $($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[allow(unsigned_negation)] impl Neg for $t { #[stable(feature = "rust1", since = "1.0.0")] type Output = $t; @@ -1024,6 +1057,10 @@ impl fmt::Debug for RangeTo { /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. /// +/// `Deref` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is accessible via dereferencing the @@ -1078,6 +1115,10 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// The `DerefMut` trait is used to specify the functionality of dereferencing /// mutably like `*v = 1;` /// +/// `DerefMut` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is modifiable via dereferencing the @@ -1233,3 +1274,120 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + +/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +#[unstable(feature = "placement_new_protocol")] +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `in (PLACE) EXPR`. +/// +/// `in (PLACE) EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +#[unstable(feature = "placement_new_protocol")] +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `in (PLACE) EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `in (PLACE) EXPR` + /// + /// Note that when `in (PLACE) EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +#[unstable(feature = "placement_new_protocol")] +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place: BoxPlace; + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index c5203c5111b64..9ccba7ad78d45 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -46,7 +46,7 @@ //! // The division was valid //! Some(x) => println!("Result: {}", x), //! // The division was invalid -//! None => println!("Cannot divide by 0") +//! None => println!("Cannot divide by 0"), //! } //! ``` //! @@ -75,7 +75,7 @@ //! fn check_optional(optional: &Option>) { //! match *optional { //! Some(ref p) => println!("have value {}", p), -//! None => println!("have no value") +//! None => println!("have no value"), //! } //! } //! ``` @@ -95,13 +95,13 @@ //! // Take a reference to the contained string //! match msg { //! Some(ref m) => println!("{}", *m), -//! None => () +//! None => (), //! } //! //! // Remove the contained string, destroying the Option //! let unwrapped_msg = match msg { //! Some(m) => m, -//! None => "default message" +//! None => "default message", //! }; //! ``` //! @@ -137,7 +137,7 @@ //! //! match name_of_biggest_animal { //! Some(name) => println!("the biggest animal is {}", name), -//! None => println!("there are no animals :(") +//! None => println!("there are no animals :("), //! } //! ``` @@ -198,7 +198,7 @@ impl Option { pub fn is_some(&self) -> bool { match *self { Some(_) => true, - None => false + None => false, } } @@ -244,7 +244,7 @@ impl Option { pub fn as_ref<'r>(&'r self) -> Option<&'r T> { match *self { Some(ref x) => Some(x), - None => None + None => None, } } @@ -265,7 +265,7 @@ impl Option { pub fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> { match *self { Some(ref mut x) => Some(x), - None => None + None => None, } } @@ -376,7 +376,7 @@ impl Option { pub fn unwrap_or(self, def: T) -> T { match self { Some(x) => x, - None => def + None => def, } } @@ -394,7 +394,7 @@ impl Option { pub fn unwrap_or_else T>(self, f: F) -> T { match self { Some(x) => x, - None => f() + None => f(), } } @@ -420,7 +420,7 @@ impl Option { pub fn map U>(self, f: F) -> Option { match self { Some(x) => Some(f(x)), - None => None + None => None, } } @@ -464,7 +464,7 @@ impl Option { pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { match self { Some(t) => f(t), - None => default() + None => default(), } } @@ -637,7 +637,7 @@ impl Option { pub fn or(self, optb: Option) -> Option { match self { Some(_) => self, - None => optb + None => optb, } } @@ -659,7 +659,7 @@ impl Option { pub fn or_else Option>(self, f: F) -> Option { match self { Some(_) => self, - None => f() + None => f(), } } @@ -736,7 +736,7 @@ impl Option { pub fn unwrap_or_default(self) -> T { match self { Some(x) => x, - None => Default::default() + None => Default::default(), } } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f2792a525d66b..13d95e9ab1a71 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,86 +10,11 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Operations on raw pointers, `*const T`, and `*mut T`. +//! Raw, unsafe pointers, `*const T`, and `*mut T` //! -//! Working with raw pointers in Rust is uncommon, -//! typically limited to a few patterns. -//! -//! Use the `null` function to create null pointers, and the `is_null` method -//! of the `*const T` type to check for null. The `*const T` type also defines -//! the `offset` method, for pointer math. -//! -//! # Common ways to create raw pointers -//! -//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -//! -//! ``` -//! let my_num: i32 = 10; -//! let my_num_ptr: *const i32 = &my_num; -//! let mut my_speed: i32 = 88; -//! let my_speed_ptr: *mut i32 = &mut my_speed; -//! ``` -//! -//! To get a pointer to a boxed value, dereference the box: -//! -//! ``` -//! let my_num: Box = Box::new(10); -//! let my_num_ptr: *const i32 = &*my_num; -//! let mut my_speed: Box = Box::new(88); -//! let my_speed_ptr: *mut i32 = &mut *my_speed; -//! ``` -//! -//! This does not take ownership of the original allocation -//! and requires no resource management later, -//! but you must not use the pointer after its lifetime. -//! -//! ## 2. Consume a box (`Box`). -//! -//! The `into_raw` function consumes a box and returns -//! the raw pointer. It doesn't destroy `T` or deallocate any memory. -//! -//! ``` -//! # #![feature(box_raw)] -//! use std::boxed; -//! -//! unsafe { -//! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = boxed::into_raw(my_speed); -//! -//! // By taking ownership of the original `Box` though -//! // we are obligated to put it together later to be destroyed. -//! drop(Box::from_raw(my_speed)); -//! } -//! ``` -//! -//! Note that here the call to `drop` is for clarity - it indicates -//! that we are done with the given value and it should be destroyed. -//! -//! ## 3. Get it from C. -//! -//! ``` -//! # #![feature(libc)] -//! extern crate libc; -//! -//! use std::mem; -//! -//! fn main() { -//! unsafe { -//! let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; -//! if my_num.is_null() { -//! panic!("failed to allocate memory"); -//! } -//! libc::free(my_num as *mut libc::c_void); -//! } -//! } -//! ``` -//! -//! Usually you wouldn't literally use `malloc` and `free` from Rust, -//! but C APIs hand out a lot of pointers generally, so are a common source -//! of raw pointers in Rust. +//! *[See also the pointer primitive types](../primitive.pointer.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "pointer")] use mem; use clone::Clone; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a8c995f37cce4..9339f232e9197 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -13,7 +13,6 @@ //! For more details `std::slice`. #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "slice")] // How this module is organized. // @@ -83,6 +82,8 @@ pub trait SliceExt { fn first<'a>(&'a self) -> Option<&'a Self::Item>; fn tail<'a>(&'a self) -> &'a [Self::Item]; fn init<'a>(&'a self) -> &'a [Self::Item]; + fn split_first<'a>(&'a self) -> Option<(&'a Self::Item, &'a [Self::Item])>; + fn split_last<'a>(&'a self) -> Option<(&'a Self::Item, &'a [Self::Item])>; fn last<'a>(&'a self) -> Option<&'a Self::Item>; unsafe fn get_unchecked<'a>(&'a self, index: usize) -> &'a Self::Item; fn as_ptr(&self) -> *const Self::Item; @@ -95,6 +96,8 @@ pub trait SliceExt { fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>; fn tail_mut<'a>(&'a mut self) -> &'a mut [Self::Item]; fn init_mut<'a>(&'a mut self) -> &'a mut [Self::Item]; + fn split_first_mut<'a>(&'a mut self) -> Option<(&'a mut Self::Item, &'a mut [Self::Item])>; + fn split_last_mut<'a>(&'a mut self) -> Option<(&'a mut Self::Item, &'a mut [Self::Item])>; fn last_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>; fn split_mut<'a, P>(&'a mut self, pred: P) -> SplitMut<'a, Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -238,8 +241,17 @@ impl SliceExt for [T] { fn tail(&self) -> &[T] { &self[1..] } #[inline] - fn init(&self) -> &[T] { - &self[..self.len() - 1] + fn split_first(&self) -> Option<(&T, &[T])> { + if self.is_empty() { None } else { Some((&self[0], &self[1..])) } + } + + #[inline] + fn init(&self) -> &[T] { &self[..self.len() - 1] } + + #[inline] + fn split_last(&self) -> Option<(&T, &[T])> { + let len = self.len(); + if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } } #[inline] @@ -328,8 +340,14 @@ impl SliceExt for [T] { } #[inline] - fn tail_mut(&mut self) -> &mut [T] { - &mut self[1 ..] + fn tail_mut(&mut self) -> &mut [T] { &mut self[1 ..] } + + #[inline] + fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if self.is_empty() { None } else { + let split = self.split_at_mut(1); + Some((&mut split.0[0], split.1)) + } } #[inline] @@ -338,6 +356,15 @@ impl SliceExt for [T] { &mut self[.. (len - 1)] } + #[inline] + fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + let len = self.len(); + if len == 0 { None } else { + let split = self.split_at_mut(len - 1); + Some((&mut split.1[0], split.0)) + } + } + #[inline] fn split_mut<'a, P>(&'a mut self, pred: P) -> SplitMut<'a, T, P> where P: FnMut(&T) -> bool { SplitMut { v: self, pred: pred, finished: false } @@ -1368,10 +1395,14 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] { /// /// The `len` argument is the number of **elements**, not the number of bytes. /// +/// # Unsafety +/// /// This function is unsafe as there is no guarantee that the given pointer is /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// +/// `p` must be non-null, even for zero-length slices. +/// /// # Caveat /// /// The lifetime for the returned slice is inferred from its usage. To @@ -1459,12 +1490,30 @@ pub mod bytes { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B]> for [A] where A: PartialEq { fn eq(&self, other: &[B]) -> bool { - self.len() == other.len() && - order::eq(self.iter(), other.iter()) + if self.len() != other.len() { + return false; + } + + for i in 0..self.len() { + if !self[i].eq(&other[i]) { + return false; + } + } + + true } fn ne(&self, other: &[B]) -> bool { - self.len() != other.len() || - order::ne(self.iter(), other.iter()) + if self.len() != other.len() { + return true; + } + + for i in 0..self.len() { + if self[i].ne(&other[i]) { + return true; + } + } + + false } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a621176c4a81..4f0b881c5cd60 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -12,16 +12,14 @@ //! //! For more details, see std::str -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] -use self::OldSearcher::{TwoWay, TwoWayLong}; use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::CharExt; use clone::Clone; -use cmp::{self, Eq}; +use cmp::Eq; use convert::AsRef; use default::Default; use fmt; @@ -33,7 +31,6 @@ use option::Option::{self, None, Some}; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; -use usize; pub mod pattern; @@ -638,10 +635,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split()`."] + /// Created with the method `.split()`. struct Split; reverse: - #[doc="Created with the method `.rsplit()`."] + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -652,10 +649,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split_terminator()`."] + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - #[doc="Created with the method `.rsplit_terminator()`."] + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -698,10 +695,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.splitn()`."] + /// Created with the method `.splitn()`. struct SplitN; reverse: - #[doc="Created with the method `.rsplitn()`."] + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -732,10 +729,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.match_indices()`."] + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - #[doc="Created with the method `.rmatch_indices()`."] + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "str_match_indices", @@ -773,10 +770,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.matches()`."] + /// Created with the method `.matches()`. struct Matches; reverse: - #[doc="Created with the method `.rmatches()`."] + /// Created with the method `.rmatches()`. struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] @@ -870,311 +867,16 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using two-way search -#[derive(Clone)] -struct TwoWaySearcher { - // constants - crit_pos: usize, - period: usize, - byteset: u64, - - // variables - position: usize, - memory: usize -} - -/* - This is the Two-Way search algorithm, which was introduced in the paper: - Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. - - Here's some background information. - - A *word* is a string of symbols. The *length* of a word should be a familiar - notion, and here we denote it for any word x by |x|. - (We also allow for the possibility of the *empty word*, a word of length zero). - - If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a - *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. - For example, both 1 and 2 are periods for the string "aa". As another example, - the only period of the string "abcd" is 4. - - We denote by period(x) the *smallest* period of x (provided that x is non-empty). - This is always well-defined since every non-empty word x has at least one period, - |x|. We sometimes call this *the period* of x. - - If u, v and x are words such that x = uv, where uv is the concatenation of u and - v, then we say that (u, v) is a *factorization* of x. - - Let (u, v) be a factorization for a word x. Then if w is a non-empty word such - that both of the following hold - - - either w is a suffix of u or u is a suffix of w - - either w is a prefix of v or v is a prefix of w - - then w is said to be a *repetition* for the factorization (u, v). - - Just to unpack this, there are four possibilities here. Let w = "abc". Then we - might have: - - - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") - - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") - - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") - - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") - - Note that the word vu is a repetition for any factorization (u,v) of x = uv, - so every factorization has at least one repetition. - - If x is a string and (u, v) is a factorization for x, then a *local period* for - (u, v) is an integer r such that there is some word w such that |w| = r and w is - a repetition for (u, v). - - We denote by local_period(u, v) the smallest local period of (u, v). We sometimes - call this *the local period* of (u, v). Provided that x = uv is non-empty, this - is well-defined (because each non-empty word has at least one factorization, as - noted above). - - It can be proven that the following is an equivalent definition of a local period - for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for - all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are - defined. (i.e. i > 0 and i + r < |x|). - - Using the above reformulation, it is easy to prove that - - 1 <= local_period(u, v) <= period(uv) - - A factorization (u, v) of x such that local_period(u,v) = period(x) is called a - *critical factorization*. - - The algorithm hinges on the following theorem, which is stated without proof: - - **Critical Factorization Theorem** Any word x has at least one critical - factorization (u, v) such that |u| < period(x). - - The purpose of maximal_suffix is to find such a critical factorization. - -*/ -impl TwoWaySearcher { - #[allow(dead_code)] - fn new(needle: &[u8]) -> TwoWaySearcher { - let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); - let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); - - let (crit_pos, period) = - if crit_pos_false > crit_pos_true { - (crit_pos_false, period_false) - } else { - (crit_pos_true, period_true) - }; - - // This isn't in the original algorithm, as far as I'm aware. - let byteset = needle.iter() - .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); - - // A particularly readable explanation of what's going on here can be found - // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically - // see the code for "Algorithm CP" on p. 323. - // - // What's going on is we have some critical factorization (u, v) of the - // needle, and we want to determine whether u is a suffix of - // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use - // "Algorithm CP2", which is optimized for when the period of the needle - // is large. - if &needle[..crit_pos] == &needle[period.. period + crit_pos] { - TwoWaySearcher { - crit_pos: crit_pos, - period: period, - byteset: byteset, - - position: 0, - memory: 0 - } - } else { - TwoWaySearcher { - crit_pos: crit_pos, - period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, - byteset: byteset, - - position: 0, - memory: usize::MAX // Dummy value to signify that the period is long - } - } - } - - // One of the main ideas of Two-Way is that we factorize the needle into - // two halves, (u, v), and begin trying to find v in the haystack by scanning - // left to right. If v matches, we try to match u by scanning right to left. - // How far we can jump when we encounter a mismatch is all based on the fact - // that (u, v) is a critical factorization for the needle. - #[inline] - fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) - -> Option<(usize, usize)> { - 'search: loop { - // Check that we have room to search in - if self.position + needle.len() > haystack.len() { - return None; - } - - // Quickly skip by large portions unrelated to our substring - if (self.byteset >> - ((haystack[self.position + needle.len() - 1] & 0x3f) - as usize)) & 1 == 0 { - self.position += needle.len(); - if !long_period { - self.memory = 0; - } - continue 'search; - } - - // See if the right part of the needle matches - let start = if long_period { self.crit_pos } - else { cmp::max(self.crit_pos, self.memory) }; - for i in start..needle.len() { - if needle[i] != haystack[self.position + i] { - self.position += i - self.crit_pos + 1; - if !long_period { - self.memory = 0; - } - continue 'search; - } - } - - // See if the left part of the needle matches - let start = if long_period { 0 } else { self.memory }; - for i in (start..self.crit_pos).rev() { - if needle[i] != haystack[self.position + i] { - self.position += self.period; - if !long_period { - self.memory = needle.len() - self.period; - } - continue 'search; - } - } - - // We have found a match! - let match_pos = self.position; - self.position += needle.len(); // add self.period for all matches - if !long_period { - self.memory = 0; // set to needle.len() - self.period for all matches - } - return Some((match_pos, match_pos + needle.len())); - } - } - - // Computes a critical factorization (u, v) of `arr`. - // Specifically, returns (i, p), where i is the starting index of v in some - // critical factorization (u, v) and p = period(v) - #[inline] - #[allow(dead_code)] - #[allow(deprecated)] - fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { - let mut left: usize = !0; // Corresponds to i in the paper - let mut right = 0; // Corresponds to j in the paper - let mut offset = 1; // Corresponds to k in the paper - let mut period = 1; // Corresponds to p in the paper - - while right + offset < arr.len() { - let a; - let b; - if reversed { - a = arr[left.wrapping_add(offset)]; - b = arr[right + offset]; - } else { - a = arr[right + offset]; - b = arr[left.wrapping_add(offset)]; - } - if a < b { - // Suffix is smaller, period is entire prefix so far. - right += offset; - offset = 1; - period = right.wrapping_sub(left); - } else if a == b { - // Advance through repetition of the current period. - if offset == period { - right += offset; - offset = 1; - } else { - offset += 1; - } - } else { - // Suffix is larger, start over from current location. - left = right; - right += 1; - offset = 1; - period = 1; - } - } - (left.wrapping_add(1), period) - } -} - -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using a dynamically chosen search algorithm -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -enum OldSearcher { - TwoWay(TwoWaySearcher), - TwoWayLong(TwoWaySearcher), -} - -impl OldSearcher { - #[allow(dead_code)] - fn new(haystack: &[u8], needle: &[u8]) -> OldSearcher { - if needle.is_empty() { - // Handle specially - unimplemented!() - // FIXME: Tune this. - // FIXME(#16715): This unsigned integer addition will probably not - // overflow because that would mean that the memory almost solely - // consists of the needle. Needs #16715 to be formally fixed. - } else if needle.len() + 20 > haystack.len() { - // Use naive searcher - unimplemented!() - } else { - let searcher = TwoWaySearcher::new(needle); - if searcher.memory == usize::MAX { // If the period is long - TwoWayLong(searcher) - } else { - TwoWay(searcher) - } - } - } -} - -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -struct OldMatchIndices<'a, 'b> { - // constants - haystack: &'a str, - needle: &'b str, - searcher: OldSearcher -} - -impl<'a, 'b> OldMatchIndices<'a, 'b> { - #[inline] - #[allow(dead_code)] - fn next(&mut self) -> Option<(usize, usize)> { - match self.searcher { - TwoWay(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false), - TwoWayLong(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true), - } - } -} - /* Section: Comparing strings */ -// share the implementation of the lang-item vs. non-lang-item -// eq_slice. +/// Bytewise slice equality /// NOTE: This function is (ab)used in rustc::middle::trans::_match /// to compare &[u8] byte slices that are not necessarily valid UTF-8. +#[lang = "str_eq"] #[inline] -fn eq_slice_(a: &str, b: &str) -> bool { +fn eq_slice(a: &str, b: &str) -> bool { // NOTE: In theory n should be libc::size_t and not usize, but libc is not available here #[allow(improper_ctypes)] extern { fn memcmp(s1: *const i8, s2: *const i8, n: usize) -> i32; } @@ -1185,15 +887,6 @@ fn eq_slice_(a: &str, b: &str) -> bool { } } -/// Bytewise slice equality -/// NOTE: This function is (ab)used in rustc::middle::trans::_match -/// to compare &[u8] byte slices that are not necessarily valid UTF-8. -#[lang = "str_eq"] -#[inline] -fn eq_slice(a: &str, b: &str) -> bool { - eq_slice_(a, b) -} - /* Section: Misc */ @@ -1413,6 +1106,23 @@ mod traits { } } + /// Returns a mutable slice of the given string from the byte range + /// [`begin`..`end`). + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if index.start <= index.end && + self.is_char_boundary(index.start) && + self.is_char_boundary(index.end) { + unsafe { self.slice_mut_unchecked(index.start, index.end) } + } else { + super::slice_error_fail(self, index.start, index.end) + } + } + } + /// Returns a slice of the string from the beginning to byte /// `end`. /// @@ -1435,6 +1145,21 @@ mod traits { } } + /// Returns a mutable slice of the string from the beginning to byte + /// `end`. + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.end) { + unsafe { self.slice_mut_unchecked(0, index.end) } + } else { + super::slice_error_fail(self, 0, index.end) + } + } + } + /// Returns a slice of the string from `begin` to its end. /// /// Equivalent to `self[begin .. self.len()]`. @@ -1456,6 +1181,21 @@ mod traits { } } + /// Returns a slice of the string from `begin` to its end. + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.start) { + let len = self.len(); + unsafe { self.slice_mut_unchecked(index.start, len) } + } else { + super::slice_error_fail(self, index.start, self.len()) + } + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for str { type Output = str; @@ -1465,6 +1205,14 @@ mod traits { self } } + + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut for str { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { + self + } + } } /// Methods for string slices @@ -1501,6 +1249,7 @@ pub trait StrExt { fn char_len(&self) -> usize; fn slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str; unsafe fn slice_unchecked<'a>(&'a self, begin: usize, end: usize) -> &'a str; + unsafe fn slice_mut_unchecked<'a>(&'a mut self, begin: usize, end: usize) -> &'a mut str; fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool where P::Searcher: ReverseSearcher<'a>; @@ -1520,6 +1269,7 @@ pub trait StrExt { where P::Searcher: ReverseSearcher<'a>; fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; fn split_at(&self, mid: usize) -> (&str, &str); + fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str); fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>; fn subslice_offset(&self, inner: &str) -> usize; fn as_ptr(&self) -> *const u8; @@ -1676,6 +1426,14 @@ impl StrExt for str { }) } + #[inline] + unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + mem::transmute(Slice { + data: self.as_ptr().offset(begin as isize), + len: end - begin, + }) + } + #[inline] fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { pat.is_prefix_of(self) @@ -1824,6 +1582,20 @@ impl StrExt for str { } } + fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + let len = self.len(); + unsafe { + let self2: &mut str = mem::transmute_copy(&self); + (self.slice_mut_unchecked(0, mid), + self2.slice_mut_unchecked(mid, len)) + } + } else { + slice_error_fail(self, 0, mid) + } + } + #[inline] fn slice_shift_char(&self) -> Option<(char, &str)> { if self.is_empty() { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 8bdbab55211d8..707f7fcf2abcf 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -17,6 +17,8 @@ reason = "API not fully fleshed out and ready to be stabilized")] use prelude::*; +use core::cmp; +use usize; // Pattern @@ -341,148 +343,6 @@ unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> { impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {} -///////////////////////////////////////////////////////////////////////////// -// Impl for &str -///////////////////////////////////////////////////////////////////////////// - -// Todo: Optimize the naive implementation here - -/// Associated type for `<&str as Pattern<'a>>::Searcher`. -#[derive(Clone)] -pub struct StrSearcher<'a, 'b> { - haystack: &'a str, - needle: &'b str, - start: usize, - end: usize, - state: State, -} - -#[derive(Clone, PartialEq)] -enum State { Done, NotDone, Reject(usize, usize) } -impl State { - #[inline] fn done(&self) -> bool { *self == State::Done } - #[inline] fn take(&mut self) -> State { ::mem::replace(self, State::NotDone) } -} - -/// Non-allocating substring search. -/// -/// Will handle the pattern `""` as returning empty matches at each utf8 -/// boundary. -impl<'a, 'b> Pattern<'a> for &'b str { - type Searcher = StrSearcher<'a, 'b>; - - #[inline] - fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { - StrSearcher { - haystack: haystack, - needle: self, - start: 0, - end: haystack.len(), - state: State::NotDone, - } - } -} - -unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn haystack(&self) -> &'a str { - self.haystack - } - - #[inline] - fn next(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Forward step for empty needle - let current_start = m.start; - if !m.state.done() { - m.start = m.haystack.char_range_at(current_start).next; - m.state = State::Reject(current_start, m.start); - } - SearchStep::Match(current_start, current_start) - }, - |m: &mut StrSearcher| { - // Forward step for nonempty needle - let current_start = m.start; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()]; - if possible_match == m.needle.as_bytes() { - m.start += m.needle.len(); - SearchStep::Match(current_start, m.start) - } else { - // Skip a char - let haystack_suffix = &m.haystack[m.start..]; - m.start += haystack_suffix.chars().next().unwrap().len_utf8(); - SearchStep::Reject(current_start, m.start) - } - }) - } -} - -unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn next_back(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Backward step for empty needle - let current_end = m.end; - if !m.state.done() { - m.end = m.haystack.char_range_at_reverse(current_end).next; - m.state = State::Reject(m.end, current_end); - } - SearchStep::Match(current_end, current_end) - }, - |m: &mut StrSearcher| { - // Backward step for nonempty needle - let current_end = m.end; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end]; - if possible_match == m.needle.as_bytes() { - m.end -= m.needle.len(); - SearchStep::Match(m.end, current_end) - } else { - // Skip a char - let haystack_prefix = &m.haystack[..m.end]; - m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8(); - SearchStep::Reject(m.end, current_end) - } - }) - } -} - -// Helper function for encapsulating the common control flow -// of doing a search step from the front or doing a search step from the back -fn str_search_step(mut m: &mut StrSearcher, - empty_needle_step: F, - nonempty_needle_step: G) -> SearchStep - where F: FnOnce(&mut StrSearcher) -> SearchStep, - G: FnOnce(&mut StrSearcher) -> SearchStep -{ - if m.state.done() { - SearchStep::Done - } else if m.needle.is_empty() && m.start <= m.end { - // Case for needle == "" - if let State::Reject(a, b) = m.state.take() { - SearchStep::Reject(a, b) - } else { - if m.start == m.end { - m.state = State::Done; - } - empty_needle_step(&mut m) - } - } else if m.start + m.needle.len() <= m.end { - // Case for needle != "" - nonempty_needle_step(&mut m) - } else if m.start < m.end { - // Remaining slice shorter than needle, reject it - m.state = State::Done; - SearchStep::Reject(m.start, m.end) - } else { - m.state = State::Done; - SearchStep::Done - } -} - ///////////////////////////////////////////////////////////////////////////// macro_rules! pattern_methods { @@ -633,3 +493,578 @@ impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { impl<'a, 'b> Pattern<'a> for &'b &'b str { pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); } + +///////////////////////////////////////////////////////////////////////////// +// Impl for &str +///////////////////////////////////////////////////////////////////////////// + +/// Non-allocating substring search. +/// +/// Will handle the pattern `""` as returning empty matches at each character +/// boundary. +impl<'a, 'b> Pattern<'a> for &'b str { + type Searcher = StrSearcher<'a, 'b>; + + #[inline] + fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { + StrSearcher::new(haystack, self) + } + + /// Checks whether the pattern matches at the front of the haystack + #[inline] + fn is_prefix_of(self, haystack: &'a str) -> bool { + haystack.is_char_boundary(self.len()) && + self == &haystack[..self.len()] + } + + /// Checks whether the pattern matches at the back of the haystack + #[inline] + fn is_suffix_of(self, haystack: &'a str) -> bool { + self.len() <= haystack.len() && + haystack.is_char_boundary(haystack.len() - self.len()) && + self == &haystack[haystack.len() - self.len()..] + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Two Way substring searcher +///////////////////////////////////////////////////////////////////////////// + +#[derive(Clone, Debug)] +/// Associated type for `<&str as Pattern<'a>>::Searcher`. +pub struct StrSearcher<'a, 'b> { + haystack: &'a str, + needle: &'b str, + + searcher: StrSearcherImpl, +} + +#[derive(Clone, Debug)] +enum StrSearcherImpl { + Empty(EmptyNeedle), + TwoWay(TwoWaySearcher), +} + +#[derive(Clone, Debug)] +struct EmptyNeedle { + position: usize, + end: usize, + is_match_fw: bool, + is_match_bw: bool, +} + +impl<'a, 'b> StrSearcher<'a, 'b> { + fn new(haystack: &'a str, needle: &'b str) -> StrSearcher<'a, 'b> { + if needle.is_empty() { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::Empty(EmptyNeedle { + position: 0, + end: haystack.len(), + is_match_fw: true, + is_match_bw: true, + }), + } + } else { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::TwoWay( + TwoWaySearcher::new(needle.as_bytes(), haystack.len()) + ), + } + } + } +} + +unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { + fn haystack(&self) -> &'a str { self.haystack } + + #[inline] + fn next(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + // empty needle rejects every char and matches every empty string between them + let is_match = searcher.is_match_fw; + searcher.is_match_fw = !searcher.is_match_fw; + let pos = searcher.position; + match self.haystack[pos..].chars().next() { + _ if is_match => SearchStep::Match(pos, pos), + None => SearchStep::Done, + Some(ch) => { + searcher.position += ch.len_utf8(); + SearchStep::Reject(pos, searcher.position) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + // TwoWaySearcher produces valid *Match* indices that split at char boundaries + // as long as it does correct matching and that haystack and needle are + // valid UTF-8 + // *Rejects* from the algorithm can fall on any indices, but we will walk them + // manually to the next character boundary, so that they are utf-8 safe. + if searcher.position == self.haystack.len() { + return SearchStep::Done; + } + let is_long = searcher.memory == usize::MAX; + match searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + is_long) + { + SearchStep::Reject(a, mut b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(b) { + b += 1; + } + searcher.position = cmp::max(b, searcher.position); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline(always)] + fn next_match(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + let is_long = searcher.memory == usize::MAX; + if is_long { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + true) + } else { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + false) + } + } + } + } + +} +unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { + #[inline] + fn next_back(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + let is_match = searcher.is_match_bw; + searcher.is_match_bw = !searcher.is_match_bw; + let end = searcher.end; + match self.haystack[..end].chars().next_back() { + _ if is_match => SearchStep::Match(end, end), + None => SearchStep::Done, + Some(ch) => { + searcher.end -= ch.len_utf8(); + SearchStep::Reject(searcher.end, end) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + if searcher.end == 0 { + return SearchStep::Done; + } + match searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + { + SearchStep::Reject(mut a, b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(a) { + a -= 1; + } + searcher.end = cmp::min(a, searcher.end); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline] + fn next_match_back(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next_back() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + } + } + } +} + +/// The internal state of an iterator that searches for matches of a substring +/// within a larger string using two-way search +#[derive(Clone, Debug)] +struct TwoWaySearcher { + // constants + crit_pos: usize, + period: usize, + byteset: u64, + + // variables + position: usize, + end: usize, + memory: usize +} + +/* + This is the Two-Way search algorithm, which was introduced in the paper: + Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. + + Here's some background information. + + A *word* is a string of symbols. The *length* of a word should be a familiar + notion, and here we denote it for any word x by |x|. + (We also allow for the possibility of the *empty word*, a word of length zero). + + If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a + *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. + For example, both 1 and 2 are periods for the string "aa". As another example, + the only period of the string "abcd" is 4. + + We denote by period(x) the *smallest* period of x (provided that x is non-empty). + This is always well-defined since every non-empty word x has at least one period, + |x|. We sometimes call this *the period* of x. + + If u, v and x are words such that x = uv, where uv is the concatenation of u and + v, then we say that (u, v) is a *factorization* of x. + + Let (u, v) be a factorization for a word x. Then if w is a non-empty word such + that both of the following hold + + - either w is a suffix of u or u is a suffix of w + - either w is a prefix of v or v is a prefix of w + + then w is said to be a *repetition* for the factorization (u, v). + + Just to unpack this, there are four possibilities here. Let w = "abc". Then we + might have: + + - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") + - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") + - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") + - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") + + Note that the word vu is a repetition for any factorization (u,v) of x = uv, + so every factorization has at least one repetition. + + If x is a string and (u, v) is a factorization for x, then a *local period* for + (u, v) is an integer r such that there is some word w such that |w| = r and w is + a repetition for (u, v). + + We denote by local_period(u, v) the smallest local period of (u, v). We sometimes + call this *the local period* of (u, v). Provided that x = uv is non-empty, this + is well-defined (because each non-empty word has at least one factorization, as + noted above). + + It can be proven that the following is an equivalent definition of a local period + for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for + all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are + defined. (i.e. i > 0 and i + r < |x|). + + Using the above reformulation, it is easy to prove that + + 1 <= local_period(u, v) <= period(uv) + + A factorization (u, v) of x such that local_period(u,v) = period(x) is called a + *critical factorization*. + + The algorithm hinges on the following theorem, which is stated without proof: + + **Critical Factorization Theorem** Any word x has at least one critical + factorization (u, v) such that |u| < period(x). + + The purpose of maximal_suffix is to find such a critical factorization. + +*/ +impl TwoWaySearcher { + fn new(needle: &[u8], end: usize) -> TwoWaySearcher { + let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); + let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); + + let (crit_pos, period) = + if crit_pos_false > crit_pos_true { + (crit_pos_false, period_false) + } else { + (crit_pos_true, period_true) + }; + + // This isn't in the original algorithm, as far as I'm aware. + let byteset = needle.iter() + .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); + + // A particularly readable explanation of what's going on here can be found + // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically + // see the code for "Algorithm CP" on p. 323. + // + // What's going on is we have some critical factorization (u, v) of the + // needle, and we want to determine whether u is a suffix of + // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use + // "Algorithm CP2", which is optimized for when the period of the needle + // is large. + if &needle[..crit_pos] == &needle[period.. period + crit_pos] { + // short period case + TwoWaySearcher { + crit_pos: crit_pos, + period: period, + byteset: byteset, + + position: 0, + end: end, + memory: 0 + } + } else { + // long period case + // we have an approximation to the actual period, and don't use memory. + TwoWaySearcher { + crit_pos: crit_pos, + period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, + byteset: byteset, + + position: 0, + end: end, + memory: usize::MAX // Dummy value to signify that the period is long + } + } + } + + #[inline(always)] + fn byteset_contains(&self, byte: u8) -> bool { + (self.byteset >> ((byte & 0x3f) as usize)) & 1 != 0 + } + + // One of the main ideas of Two-Way is that we factorize the needle into + // two halves, (u, v), and begin trying to find v in the haystack by scanning + // left to right. If v matches, we try to match u by scanning right to left. + // How far we can jump when we encounter a mismatch is all based on the fact + // that (u, v) is a critical factorization for the needle. + #[inline(always)] + fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) + -> S::Output + where S: TwoWayStrategy + { + // `next()` uses `self.position` as its cursor + let old_pos = self.position; + 'search: loop { + // Check that we have room to search in + if needle.len() > haystack.len() - self.position { + self.position = haystack.len(); + return S::rejecting(old_pos, self.position); + } + + if S::use_early_reject() && old_pos != self.position { + return S::rejecting(old_pos, self.position); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.position + needle.len() - 1]) { + self.position += needle.len(); + if !long_period { + self.memory = 0; + } + continue 'search; + } + + // See if the right part of the needle matches + let start = if long_period { self.crit_pos } + else { cmp::max(self.crit_pos, self.memory) }; + for i in start..needle.len() { + if needle[i] != haystack[self.position + i] { + self.position += i - self.crit_pos + 1; + if !long_period { + self.memory = 0; + } + continue 'search; + } + } + + // See if the left part of the needle matches + let start = if long_period { 0 } else { self.memory }; + for i in (start..self.crit_pos).rev() { + if needle[i] != haystack[self.position + i] { + self.position += self.period; + if !long_period { + self.memory = needle.len() - self.period; + } + continue 'search; + } + } + + // We have found a match! + let match_pos = self.position; + + // Note: add self.period instead of needle.len() to have overlapping matches + self.position += needle.len(); + if !long_period { + self.memory = 0; // set to needle.len() - self.period for overlapping matches + } + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Follows the ideas in `next()`. + // + // All the definitions are completely symmetrical, with period(x) = period(reverse(x)) + // and local_period(u, v) = local_period(reverse(v), reverse(u)), so if (u, v) + // is a critical factorization, so is (reverse(v), reverse(u)). Similarly, + // the "period" stored in self.period is the real period if long_period is + // false, and so is still valid for a reversed needle, and if long_period is + // true, all the algorithm requires is that self.period is less than or + // equal to the real period, which must be true for the forward case anyway. + // + // To search in reverse through the haystack, we search forward through + // a reversed haystack with a reversed needle, and the above paragraph shows + // that the precomputed parameters can be left alone. + #[inline] + fn next_back(&mut self, haystack: &[u8], needle: &[u8]) + -> S::Output + where S: TwoWayStrategy + { + // `next_back()` uses `self.end` as its cursor -- so that `next()` and `next_back()` + // are independent. + let old_end = self.end; + 'search: loop { + // Check that we have room to search in + if needle.len() > self.end { + self.end = 0; + return S::rejecting(0, old_end); + } + + if S::use_early_reject() && old_end != self.end { + return S::rejecting(self.end, old_end); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.end - needle.len()]) { + self.end -= needle.len(); + continue 'search; + } + + // See if the left part of the needle matches + for i in (0..self.crit_pos).rev() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.crit_pos - i; + continue 'search; + } + } + + // See if the right part of the needle matches + for i in self.crit_pos..needle.len() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.period; + continue 'search; + } + } + + // We have found a match! + let match_pos = self.end - needle.len(); + // Note: sub self.period instead of needle.len() to have overlapping matches + self.end -= needle.len(); + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Computes a critical factorization (u, v) of `arr`. + // Specifically, returns (i, p), where i is the starting index of v in some + // critical factorization (u, v) and p = period(v) + #[inline] + fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { + let mut left: usize = !0; // Corresponds to i in the paper + let mut right = 0; // Corresponds to j in the paper + let mut offset = 1; // Corresponds to k in the paper + let mut period = 1; // Corresponds to p in the paper + + while right + offset < arr.len() { + let a; + let b; + if reversed { + a = arr[left.wrapping_add(offset)]; + b = arr[right + offset]; + } else { + a = arr[right + offset]; + b = arr[left.wrapping_add(offset)]; + } + if a < b { + // Suffix is smaller, period is entire prefix so far. + right += offset; + offset = 1; + period = right.wrapping_sub(left); + } else if a == b { + // Advance through repetition of the current period. + if offset == period { + right += offset; + offset = 1; + } else { + offset += 1; + } + } else { + // Suffix is larger, start over from current location. + left = right; + right += 1; + offset = 1; + period = 1; + } + } + (left.wrapping_add(1), period) + } +} + +// TwoWayStrategy allows the algorithm to either skip non-matches as quickly +// as possible, or to work in a mode where it emits Rejects relatively quickly. +trait TwoWayStrategy { + type Output; + fn use_early_reject() -> bool; + fn rejecting(usize, usize) -> Self::Output; + fn matching(usize, usize) -> Self::Output; +} + +/// Skip to match intervals as quickly as possible +enum MatchOnly { } + +impl TwoWayStrategy for MatchOnly { + type Output = Option<(usize, usize)>; + + #[inline] + fn use_early_reject() -> bool { false } + #[inline] + fn rejecting(_a: usize, _b: usize) -> Self::Output { None } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { Some((a, b)) } +} + +/// Emit Rejects regularly +enum RejectAndMatch { } + +impl TwoWayStrategy for RejectAndMatch { + type Output = SearchStep; + + #[inline] + fn use_early_reject() -> bool { true } + #[inline] + fn rejecting(a: usize, b: usize) -> Self::Output { SearchStep::Reject(a, b) } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { SearchStep::Match(a, b) } +} diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index ba6a7c4a5fefa..6c5ff22232365 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on tuples +//! A finite heterogeneous sequence, `(T, U, ..)` //! //! To access a single element of a tuple one can use the `.0` //! field access syntax. @@ -28,7 +28,6 @@ //! * `Default` #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "tuple")] use clone::Clone; use cmp::*; diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 1506982586a00..35f8372a70948 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -102,29 +102,6 @@ fn test_to_uppercase() { assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']); } -#[test] -fn test_to_titlecase() { - fn title(c: char) -> Vec { - c.to_titlecase().collect() - } - assert_eq!(title('a'), ['A']); - assert_eq!(title('ö'), ['Ö']); - assert_eq!(title('ß'), ['S', 's']); // not ẞ: Latin capital letter sharp s - assert_eq!(title('ü'), ['Ü']); - assert_eq!(title('💩'), ['💩']); - - assert_eq!(title('σ'), ['Σ']); - assert_eq!(title('τ'), ['Τ']); - assert_eq!(title('ι'), ['Ι']); - assert_eq!(title('γ'), ['Γ']); - assert_eq!(title('μ'), ['Μ']); - assert_eq!(title('α'), ['Α']); - assert_eq!(title('ς'), ['Σ']); - assert_eq!(title('DŽ'), ['Dž']); - assert_eq!(title('fi'), ['F', 'i']); - assert_eq!(title('ᾀ'), ['ᾈ']); -} - #[test] fn test_is_control() { assert!('\u{0}'.is_control()); diff --git a/src/libcoretest/fmt/mod.rs b/src/libcoretest/fmt/mod.rs index cdb9c38f027f7..42872589bb01f 100644 --- a/src/libcoretest/fmt/mod.rs +++ b/src/libcoretest/fmt/mod.rs @@ -16,4 +16,6 @@ fn test_format_flags() { // No residual flags left by pointer formatting let p = "".as_ptr(); assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p)); + + assert_eq!(format!("{: >3}", 'a'), " a"); } diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index cab2175f89781..247c3dcb9c705 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unsigned_negation)] - use core::fmt::radix; #[test] diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 5c11f0196aeb8..697c3ee254b98 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod sip; + use std::mem; use std::hash::{Hash, Hasher}; use std::default::Default; diff --git a/src/libcoretest/hash/sip.rs b/src/libcoretest/hash/sip.rs index 8289d06d04c61..7832985d3f1c1 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcoretest/hash/sip.rs @@ -8,28 +8,55 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use test::Bencher; -use std::prelude::*; -use std::fmt; -use str::Str; -use string::String; -use slice::{AsSlice, SlicePrelude}; -use vec::Vec; - -use core::hash::{Hash, Writer}; -use core::hash::sip::{SipState, hash, hash_with_keys}; +use core::hash::{Hash, Hasher}; +use core::hash::SipHasher; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); -impl<'a, S: Writer> Hash for Bytes<'a> { +impl<'a> Hash for Bytes<'a> { #[allow(unused_must_use)] - fn hash(&self, state: &mut S) { + fn hash(&self, state: &mut H) { let Bytes(v) = *self; state.write(v); } } +macro_rules! u8to64_le { + ($buf:expr, $i:expr) => + ($buf[0+$i] as u64 | + ($buf[1+$i] as u64) << 8 | + ($buf[2+$i] as u64) << 16 | + ($buf[3+$i] as u64) << 24 | + ($buf[4+$i] as u64) << 32 | + ($buf[5+$i] as u64) << 40 | + ($buf[6+$i] as u64) << 48 | + ($buf[7+$i] as u64) << 56); + ($buf:expr, $i:expr, $len:expr) => + ({ + let mut t = 0; + let mut out = 0; + while t < $len { + out |= ($buf[t+$i] as u64) << t*8; + t += 1; + } + out + }); +} + +fn hash(x: &T) -> u64 { + let mut st = SipHasher::new(); + x.hash(&mut st); + st.finish() +} + +fn hash_with_keys(k1: u64, k2: u64, x: &T) -> u64 { + let mut st = SipHasher::new_with_keys(k1, k2); + x.hash(&mut st); + st.finish() +} + #[test] #[allow(unused_must_use)] fn test_siphash() { @@ -104,79 +131,43 @@ fn test_siphash() { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; let mut buf = Vec::new(); let mut t = 0; - let mut state_inc = SipState::new_with_keys(k0, k1); - let mut state_full = SipState::new_with_keys(k0, k1); - - fn to_hex_str(r: &[u8; 8]) -> String { - let mut s = String::new(); - for b in r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } - - fn result_bytes(h: u64) -> Vec { - vec![(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(h: u64) -> String { - let r = result_bytes(h); - let mut s = String::new(); - for b in &r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } + let mut state_inc = SipHasher::new_with_keys(k0, k1); while t < 64 { - debug!("siphash test {}: {}", t, buf); let vec = u8to64_le!(vecs[t], 0); - let out = hash_with_keys(k0, k1, &Bytes(buf)); - debug!("got {}, expected {}", out, vec); + let out = hash_with_keys(k0, k1, &Bytes(&buf)); assert_eq!(vec, out); - state_full.reset(); - state_full.write(buf); - let f = result_str(state_full.result()); - let i = result_str(state_inc.result()); - let v = to_hex_str(&vecs[t]); - debug!("{}: ({}) => inc={} full={}", t, v, i, f); + let full = hash_with_keys(k0, k1, &Bytes(&buf)); + let i = state_inc.finish(); - assert_eq!(f, i); - assert_eq!(f, v); + assert_eq!(full, i); + assert_eq!(full, vec); buf.push(t as u8); - state_inc.write(&[t as u8]); + Hasher::write(&mut state_inc, &[t as u8]); t += 1; } } #[test] #[cfg(target_arch = "arm")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86_64")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); + assert_eq!(hash(&(val as u64)), hash(&(val as usize))); + assert!(hash(&(val as u32)) != hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] @@ -200,7 +191,7 @@ fn test_hash_no_bytes_dropped_64() { assert!(hash(&val) != hash(&zero_byte(val, 6))); assert!(hash(&val) != hash(&zero_byte(val, 7))); - fn zero_byte(val: u64, byte: uint) -> u64 { + fn zero_byte(val: u64, byte: usize) -> u64 { assert!(byte < 8); val & !(0xff << (byte * 8)) } @@ -215,7 +206,7 @@ fn test_hash_no_bytes_dropped_32() { assert!(hash(&val) != hash(&zero_byte(val, 2))); assert!(hash(&val) != hash(&zero_byte(val, 3))); - fn zero_byte(val: u32, byte: uint) -> u32 { + fn zero_byte(val: u32, byte: usize) -> u32 { assert!(byte < 4); val & !(0xff << (byte * 8)) } @@ -230,8 +221,9 @@ fn test_hash_no_concat_alias() { assert!(s != t && t != u); assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - let v: (&[u8], &[u8], &[u8]) = (&[1], &[0, 0], &[0]); - let w: (&[u8], &[u8], &[u8]) = (&[1, 0, 0, 0], &[], &[]); + let u = [1, 0, 0, 0]; + let v = (&u[..1], &u[1..3], &u[3..]); + let w = (&u[..], &u[4..4], &u[4..4]); assert!(v != w); assert!(hash(&v) != hash(&w)); diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 998f4b21ece7f..a9baa2cc477f6 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -117,7 +117,14 @@ mod tests { } #[test] - fn test_int_from_minus_sign() { - assert_eq!("-".parse::().ok(), None); + fn test_invalid() { + assert_eq!("--129".parse::().ok(), None); + assert_eq!("Съешь".parse::().ok(), None); + } + + #[test] + fn test_empty() { + assert_eq!("-".parse::().ok(), None); + assert_eq!("".parse::().ok(), None); } } diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 8f1017c50a39d..865b049aae55a 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -10,7 +10,6 @@ use core::ptr::*; use core::mem; -use std::iter::repeat; #[test] fn test() { @@ -110,7 +109,7 @@ fn test_as_mut() { #[test] fn test_ptr_addition() { unsafe { - let xs = repeat(5).take(16).collect::>(); + let xs = vec![5; 16]; let mut ptr = xs.as_ptr(); let end = ptr.offset(16); @@ -128,7 +127,7 @@ fn test_ptr_addition() { m_ptr = m_ptr.offset(1); } - assert!(xs_mut == repeat(10).take(16).collect::>()); + assert!(xs_mut == vec![10; 16]); } } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index c2b28bd134d47..7ca89cfd0c9cc 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { } Some(..) | None => { return &self.input[..0]; } }; - let mut end; + let end; loop { match self.cur.clone().next() { Some((_, c)) if c.is_xid_continue() => { diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 0d15f584d648a..8953375297db2 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -56,7 +56,7 @@ //! optopt("o", "", "set output file name", "NAME"), //! optflag("h", "help", "print this help menu") //! ]; -//! let matches = match getopts(args.tail(), opts) { +//! let matches = match getopts(args[1..], opts) { //! Ok(m) => { m } //! Err(f) => { panic!(f.to_string()) } //! }; @@ -784,13 +784,13 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> String { // FIXME: #5516 should be graphemes not codepoints // wrapped description - row.push_str(&desc_rows.connect(&desc_sep[..])); + row.push_str(&desc_rows.join(&desc_sep[..])); row }); format!("{}\n\nOptions:\n{}\n", brief, - rows.collect::>().connect("\n")) + rows.collect::>().join("\n")) } fn format_option(opt: &OptGroup) -> String { @@ -836,7 +836,7 @@ pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { line.push_str(&opts.iter() .map(format_option) .collect::>() - .connect(" ")[..]); + .join(" ")[..]); line } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index f8d80035d97fb..4d07573268a68 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -312,6 +312,40 @@ pub enum LabelText<'a> { EscStr(Cow<'a, str>), } +/// The style for a node or edge. +/// See http://www.graphviz.org/doc/info/attrs.html#k:style for descriptions. +/// Note that some of these are not valid for edges. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Style { + None, + Solid, + Dashed, + Dotted, + Bold, + Rounded, + Diagonals, + Filled, + Striped, + Wedged, +} + +impl Style { + pub fn as_slice(self) -> &'static str { + match self { + Style::None => "", + Style::Solid => "solid", + Style::Dashed => "dashed", + Style::Dotted => "dotted", + Style::Bold => "bold", + Style::Rounded => "rounded", + Style::Diagonals => "diagonals", + Style::Filled => "filled", + Style::Striped => "striped", + Style::Wedged => "wedged", + } + } +} + // There is a tension in the design of the labelling API. // // For example, I considered making a `Labeller` trait that @@ -430,6 +464,16 @@ pub trait Labeller<'a,N,E> { let _ignored = e; LabelStr("".into_cow()) } + + /// Maps `n` to a style that will be used in the rendered output. + fn node_style(&'a self, _n: &N) -> Style { + Style::None + } + + /// Maps `e` to a style that will be used in the rendered output. + fn edge_style(&'a self, _e: &E) -> Style { + Style::None + } } impl<'a> LabelText<'a> { @@ -529,6 +573,8 @@ pub trait GraphWalk<'a, N, E> { pub enum RenderOption { NoEdgeLabels, NoNodeLabels, + NoEdgeStyles, + NoNodeStyles, } /// Returns vec holding all the default render options. @@ -562,30 +608,53 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N for n in g.nodes().iter() { try!(indent(w)); let id = g.node_id(n); - if options.contains(&RenderOption::NoNodeLabels) { - try!(writeln(w, &[id.as_slice(), ";"])); - } else { - let escaped = g.node_label(n).escape(); - try!(writeln(w, &[id.as_slice(), - "[label=\"", &escaped, "\"];"])); + + let escaped = &g.node_label(n).escape(); + + let mut text = vec![id.as_slice()]; + + if !options.contains(&RenderOption::NoNodeLabels) { + text.push("[label=\""); + text.push(escaped); + text.push("\"]"); + } + + let style = g.node_style(n); + if !options.contains(&RenderOption::NoNodeStyles) && style != Style::None { + text.push("[style=\""); + text.push(style.as_slice()); + text.push("\"]"); } + + text.push(";"); + try!(writeln(w, &text)); } for e in g.edges().iter() { - let escaped_label = g.edge_label(e).escape(); + let escaped_label = &g.edge_label(e).escape(); try!(indent(w)); let source = g.source(e); let target = g.target(e); let source_id = g.node_id(&source); let target_id = g.node_id(&target); - if options.contains(&RenderOption::NoEdgeLabels) { - try!(writeln(w, &[source_id.as_slice(), - " -> ", target_id.as_slice(), ";"])); - } else { - try!(writeln(w, &[source_id.as_slice(), - " -> ", target_id.as_slice(), - "[label=\"", &escaped_label, "\"];"])); + + let mut text = vec![source_id.as_slice(), " -> ", target_id.as_slice()]; + + if !options.contains(&RenderOption::NoEdgeLabels) { + text.push("[label=\""); + text.push(escaped_label); + text.push("\"]"); + } + + let style = g.edge_style(e); + if !options.contains(&RenderOption::NoEdgeStyles) && style != Style::None { + text.push("[style=\""); + text.push(style.as_slice()); + text.push("\"]"); } + + text.push(";"); + try!(writeln(w, &text)); } writeln(w, &["}"]) @@ -594,21 +663,23 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N #[cfg(test)] mod tests { use self::NodeLabels::*; - use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; + use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style}; use super::LabelText::{self, LabelStr, EscStr}; use std::io; use std::io::prelude::*; use std::borrow::IntoCow; - use std::iter::repeat; /// each node is an index in a vector in the graph. type Node = usize; struct Edge { - from: usize, to: usize, label: &'static str + from: usize, + to: usize, + label: &'static str, + style: Style, } - fn edge(from: usize, to: usize, label: &'static str) -> Edge { - Edge { from: from, to: to, label: label } + fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge { + Edge { from: from, to: to, label: label, style: style } } struct LabelledGraph { @@ -624,6 +695,8 @@ mod tests { /// text. node_labels: Vec>, + node_styles: Vec