mirror of
https://git.proxmox.com/git/rustc
synced 2025-06-28 01:46:13 +00:00
Imported Upstream version 0.7
This commit is contained in:
parent
223e47cc31
commit
970d7e83e1
228
AUTHORS.txt
Normal file
228
AUTHORS.txt
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
Initial author, project lead, target of blame:
|
||||||
|
|
||||||
|
Graydon Hoare <graydon@mozilla.com>
|
||||||
|
|
||||||
|
Other authors:
|
||||||
|
|
||||||
|
|
||||||
|
Adam Bozanich <adam.boz@gmail.com>
|
||||||
|
Aleksander Balicki <balicki.aleksander@gmail.com>
|
||||||
|
Alex Crichton <alex@alexcrichton.com>
|
||||||
|
Alex Rønne Petersen <alex@lycus.org>
|
||||||
|
Alexander Stavonin <a.stavonin@gmail.com>
|
||||||
|
Alexei Sholik <alcosholik@gmail.com>
|
||||||
|
Andreas Gal <gal@mozilla.com>
|
||||||
|
Andrew Dunham <andrew@du.nham.ca>
|
||||||
|
Andrew Paseltiner <apaseltiner@gmail.com>
|
||||||
|
Anthony Juckel <ajuckel@gmail.com>
|
||||||
|
Arkaitz Jimenez <arkaitzj@gmail.com>
|
||||||
|
Armin Ronacher <armin.ronacher@active-4.com>
|
||||||
|
Ashok Gautham <ScriptDevil@gmail.com>
|
||||||
|
Austin Seipp <mad.one@gmail.com>
|
||||||
|
Aydin Kim <ladinjin@hanmail.net>
|
||||||
|
auREAX <mark@xn--hwg34fba.ws>
|
||||||
|
Ben Alpert <ben@benalpert.com>
|
||||||
|
Ben Blum <bblum@andrew.cmu.edu>
|
||||||
|
Ben Kelly <ben@wanderview.com>
|
||||||
|
Ben Striegel <ben.striegel@gmail.com>
|
||||||
|
Benjamin Herr <ben@0x539.de>
|
||||||
|
Benjamin Jackman <ben@jackman.biz>
|
||||||
|
Benjamin Kircher <benjamin.kircher@gmail.com>
|
||||||
|
Benjamin Peterson <benjamin@python.org>
|
||||||
|
Bilal Husain <bilal@bilalhusain.com>
|
||||||
|
Bill Fallon <bill.fallon@robos.li>
|
||||||
|
Bill Myers <bill_myers@outlook.com>
|
||||||
|
Bill Wendling <wendling@apple.com>
|
||||||
|
Björn Steinbrink <bsteinbr@gmail.com>
|
||||||
|
Brendan Eich <brendan@mozilla.org>
|
||||||
|
Brendan Zabarauskas <bjzaba@yahoo.com.au>
|
||||||
|
Brett Cannon <brett@python.org>
|
||||||
|
Brian Anderson <banderson@mozilla.com>
|
||||||
|
Brian J. Burg <burg@cs.washington.edu>
|
||||||
|
Brian Leibig <brian.leibig@gmail.com>
|
||||||
|
Bryan Dunsmore <dunsmoreb@gmail.com>
|
||||||
|
Caitlin Potter <snowball@defpixel.com>
|
||||||
|
Chris Double <chris.double@double.co.nz>
|
||||||
|
Chris Peterson <cpeterson@mozilla.com>
|
||||||
|
Chris Pressey <cpressey@gmail.com>
|
||||||
|
Cody Schroeder <codys@cs.washington.edu>
|
||||||
|
Corey Richardson <corey@octayn.net>
|
||||||
|
Damian Gryski <damian@gryski.com>
|
||||||
|
Damien Grassart <damien@grassart.com>
|
||||||
|
Damien Schoof <damien.schoof@gmail.com>
|
||||||
|
Daniel Brooks <db48x@db48x.net>
|
||||||
|
Daniel Farina <daniel@fdr.io>
|
||||||
|
Dan Luu <danluu@gmail.com>
|
||||||
|
Daniel Luz <dev@mernen.com>
|
||||||
|
Daniel Micay <danielmicay@gmail.com>
|
||||||
|
Daniel Patterson <dbp@riseup.net>
|
||||||
|
Daniel Ralston <Wubbulous@gmail.com>
|
||||||
|
Daniel Ursache Dogariu <contact@danniel.net>
|
||||||
|
Dave Herman <dherman@mozilla.com>
|
||||||
|
David Forsythe <dforsythe@gmail.com>
|
||||||
|
David Klein <david.klein@baesystemsdetica.com>
|
||||||
|
David Rajchenbach-Teller <dteller@mozilla.com>
|
||||||
|
Diggory Hardy <diggory.hardy@gmail.com>
|
||||||
|
Dimitri Krassovski <labria@startika.com>
|
||||||
|
Donovan Preston <donovanpreston@gmail.com>
|
||||||
|
Drew Willcoxon <adw@mozilla.com>
|
||||||
|
Elliott Slaughter <elliottslaughter@gmail.com>
|
||||||
|
Elly Fong-Jones <elly@leptoquark.net>
|
||||||
|
Eric Holk <eric.holk@gmail.com>
|
||||||
|
Eric Holmes <eric@ejholmes.net>
|
||||||
|
Erick Tryzelaar <erick.tryzelaar@gmail.com>
|
||||||
|
Erik Rose <erik@mozilla.com>
|
||||||
|
Evan McClanahan <evan@evanmcc.com>
|
||||||
|
Fedor Indutny <fedor.indutny@gmail.com>
|
||||||
|
Felix S. Klock II <pnkfelix@pnkfx.org>
|
||||||
|
Francisco Souza <f@souza.cc>
|
||||||
|
Franklin Chen <franklinchen@franklinchen.com>
|
||||||
|
Gábor Horváth <xazax.hun@gmail.com>
|
||||||
|
Gabriel <g2p.code@gmail.com>
|
||||||
|
Gareth Daniel Smith <garethdanielsmith@gmail.com>
|
||||||
|
gifnksm <makoto.nksm@gmail.com>
|
||||||
|
Glenn Willen <gwillen@nerdnet.org>
|
||||||
|
Gonçalo Cabrita <_@gmcabrita.com>
|
||||||
|
Graham Fawcett <fawcett@uwindsor.ca>
|
||||||
|
Grahame Bowland <grahame@angrygoats.net>
|
||||||
|
Haitao Li <lihaitao@gmail.com>
|
||||||
|
hansjorg <hansjorg@gmail.com>
|
||||||
|
Herman J. Radtke III <hermanradtke@gmail.com>
|
||||||
|
Huon Wilson <dbau.pp+github@gmail.com>
|
||||||
|
Ian D. Bollinger <ian.bollinger@gmail.com>
|
||||||
|
Ilyong Cho <ilyoan@gmail.com>
|
||||||
|
Isaac Aggrey <isaac.aggrey@gmail.com>
|
||||||
|
Ivano Coppola <rgbfirefox@gmail.com>
|
||||||
|
Jack Moffitt <jack@metajack.im>
|
||||||
|
Jacob Harris Cryer Kragh <jhckragh@gmail.com>
|
||||||
|
Jacob Parker <j3parker@csclub.uwaterloo.ca>
|
||||||
|
Jakub Wieczorek <jakubw@jakubw.net>
|
||||||
|
James Miller <bladeon@gmail.com>
|
||||||
|
James Tranovich <james@openhorizonlabs.com>
|
||||||
|
Jason Orendorff <jorendorff@mozilla.com>
|
||||||
|
Jed Davis <jld@panix.com>
|
||||||
|
Jeff Balogh <jbalogh@mozilla.com>
|
||||||
|
Jeff Muizelaar <jmuizelaar@mozilla.com>
|
||||||
|
Jeff Olson <olson.jeffery@gmail.com>
|
||||||
|
Jeffrey Yasskin <jyasskin@gmail.com>
|
||||||
|
Jeong YunWon <jeong@youknowone.org>
|
||||||
|
Jens Nockert <jens@nockert.se>
|
||||||
|
Jesse Jones <jesse9jones@gmail.com>
|
||||||
|
Jesse Luehrs <doy@tozt.net>
|
||||||
|
Jesse Ruderman <jruderman@gmail.com>
|
||||||
|
Jihyun Yu <jihyun@nclab.kaist.ac.kr>
|
||||||
|
Jim Blandy <jimb@red-bean.com>
|
||||||
|
Jimmy Lu <jimmy.lu.2011@gmail.com>
|
||||||
|
J. J. Weber <jjweber@gmail.com>
|
||||||
|
Joe Pletcher <joepletcher@gmail.com>
|
||||||
|
John Clements <clements@racket-lang.org>
|
||||||
|
Jon Morton <jonanin@gmail.com>
|
||||||
|
Jonathan Sternberg <jonathansternberg@gmail.com>
|
||||||
|
Josh Matthews <josh@joshmatthews.net>
|
||||||
|
Joshua Clark <joshua.clark@txstate.edu>
|
||||||
|
Joshua Wise <joshua@joshuawise.com>
|
||||||
|
Junyoung Cho <june0.cho@samsung.com>
|
||||||
|
Jyun-Yan You <jyyou@cs.nctu.edu.tw>
|
||||||
|
Kang Seonghoon <kang.seonghoon@mearie.org>
|
||||||
|
Kelly Wilson <wilsonk@cpsc.ucalgary.ca>
|
||||||
|
Kevin Atkinson <kevina@cs.utah.edu>
|
||||||
|
Kevin Ballard <kevin@sb.org>
|
||||||
|
Kevin Cantu <me@kevincantu.org>
|
||||||
|
klutzy <klutzytheklutzy@gmail.com>
|
||||||
|
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
|
||||||
|
Laurent Bonnans <bonnans.l@gmail.com>
|
||||||
|
Lawrence Velázquez <larryv@alum.mit.edu>
|
||||||
|
Leah Hanson <astrieanna@gmail.com>
|
||||||
|
Lennart Kudling <github@kudling.de>
|
||||||
|
Lindsey Kuper <lindsey@composition.al>
|
||||||
|
Luca Bruno <lucab@debian.org>
|
||||||
|
Luqman Aden <laden@csclub.uwaterloo.ca>
|
||||||
|
Magnus Auvinen <magnus.auvinen@gmail.com>
|
||||||
|
Mahmut Bulut <mahmutbulut0@gmail.com>
|
||||||
|
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
|
||||||
|
Marijn Haverbeke <marijnh@gmail.com>
|
||||||
|
Mark Lacey <641@rudkx.com>
|
||||||
|
Mark Vian <mrv.caseus@gmail.com>
|
||||||
|
Marti Raudsepp <marti@juffo.org>
|
||||||
|
Martin DeMello <martindemello@gmail.com>
|
||||||
|
Marvin Löbel <loebel.marvin@gmail.com>
|
||||||
|
Matt Brubeck <mbrubeck@limpet.net>
|
||||||
|
Matthew McPherrin <matthew@mcpherrin.ca>
|
||||||
|
Matthew O'Connor <thegreendragon@gmail.com>
|
||||||
|
Matthijs Hofstra <thiezz@gmail.com>
|
||||||
|
Max Penet <max.penet@gmail.com>
|
||||||
|
Michael Arntzenius <daekharel@gmail.com>
|
||||||
|
Michael Bebenita <mbebenita@mozilla.com>
|
||||||
|
Michael Neumann <mneumann@ntecs.de>
|
||||||
|
Michael Sullivan <sully@msully.net>
|
||||||
|
Mikko Perttunen <cyndis@kapsi.fi>
|
||||||
|
Nick Desaulniers <ndesaulniers@mozilla.com>
|
||||||
|
Niko Matsakis <niko@alum.mit.edu>
|
||||||
|
Olivier Saut <osaut@airpost.net>
|
||||||
|
Or Brostovski <tohava@gmail.com>
|
||||||
|
Orphée Lafond-Lummis <o@orftz.com>
|
||||||
|
Patrick Walton <pwalton@mozilla.com>
|
||||||
|
Patrik Kårlin <patrik.karlin@gmail.com>
|
||||||
|
Paul Stansifer <paul.stansifer@gmail.com>
|
||||||
|
Paul Woolcock <pwoolcoc+github@gmail.com>
|
||||||
|
Pavel Panchekha <me@pavpanchekha.com>
|
||||||
|
Peter Hull <peterhull90@gmail.com>
|
||||||
|
Peter Williams <peter@newton.cx>
|
||||||
|
Philipp Brüschweiler <blei42@gmail.com>
|
||||||
|
Rafael Ávila de Espíndola <respindola@mozilla.com>
|
||||||
|
Ralph Bodenner <rkbodenner+github@gmail.com>
|
||||||
|
Ralph Giles <giles@thaumas.net>
|
||||||
|
Ramkumar Ramachandra <artagnon@gmail.com>
|
||||||
|
Reuben Morais <reuben.morais@gmail.com>
|
||||||
|
Rick Waldron <waldron.rick@gmail.com>
|
||||||
|
Rob Arnold <robarnold@cs.cmu.edu>
|
||||||
|
Rob Hoelz <rob@hoelz.ro>
|
||||||
|
Roland Tanglao <roland@rolandtanglao.com>
|
||||||
|
Ron Dahlgren <ronald.dahlgren@gmail.com>
|
||||||
|
Roy Frostig <rfrostig@mozilla.com>
|
||||||
|
Ryan Scheel <ryan.havvy@gmail.com>
|
||||||
|
Samuel Chase <samebchase@gmail.com>
|
||||||
|
Sander Mathijs van Veen <smvv@kompiler.org>
|
||||||
|
Sangeun Kim <sammy.kim@samsung.com>
|
||||||
|
Saurabh Anand <saurabhanandiit@gmail.com>
|
||||||
|
Sean Moon <ssamoon@ucla.edu>
|
||||||
|
Sean Stangl <sstangl@mozilla.com>
|
||||||
|
Sebastian N. Fernandez <cachobot@gmail.com>
|
||||||
|
Seth Pink <sethpink@gmail.com>
|
||||||
|
Seo Sanghyeon <sanxiyn@gmail.com>
|
||||||
|
sevrak <sevrak@rediffmail.com>
|
||||||
|
SiegeLord <slabode@aim.com>
|
||||||
|
Simon Barber-Dueck <sbarberdueck@gmail.com>
|
||||||
|
Simon Sapin <simon@exyr.org>
|
||||||
|
startling <tdixon51793@gmail.com>
|
||||||
|
Stefan Plantikow <stefan.plantikow@googlemail.com>
|
||||||
|
Steve Klabnik <steve@steveklabnik.com>
|
||||||
|
Steven De Coeyer <steven@banteng.be>
|
||||||
|
Steven Fackler <sfackler@gmail.com>
|
||||||
|
Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca>
|
||||||
|
Taras Shpot <mrshpot@gmail.com>
|
||||||
|
Ted Horst <ted.horst@earthlink.net>
|
||||||
|
Thad Guidry <thadguidry@gmail.com>
|
||||||
|
Thomas Daede <daede003@umn.edu>
|
||||||
|
Tim Chevalier <chevalier@alum.wellesley.edu>
|
||||||
|
Tim Taubert <tim@timtaubert.de>
|
||||||
|
Tom Lee <github@tomlee.co>
|
||||||
|
Tommy M. McGuire <mcguire@crsr.net>
|
||||||
|
Tomoki Aonuma <uasi@99cm.org>
|
||||||
|
Tony Young <tony@rfw.name>
|
||||||
|
Trinick <slicksilver555@mac.com>
|
||||||
|
Tycho Sci <tychosci@gmail.com>
|
||||||
|
Tyler Bindon <martica@martica.org>
|
||||||
|
Uwe Dauernheim <uwe@dauernheim.net>
|
||||||
|
Vadim Chugunov <vadimcn@gmail.com>
|
||||||
|
Viktor Dahl <pazaconyoman@gmail.com>
|
||||||
|
Vincent Belliard <vincent@famillebelliard.fr>
|
||||||
|
Vivek Galatage <vivekgalatage@gmail.com>
|
||||||
|
Wade Mealing <wmealing@gmail.com>
|
||||||
|
William Ting <william.h.ting@gmail.com>
|
||||||
|
Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
|
||||||
|
Young-il Choi <duddlf.choi@samsung.com>
|
||||||
|
Youngmin Yoo <youngmin.yoo@samsung.com>
|
||||||
|
Youngsoo Son <ysson83@gmail.com>
|
||||||
|
Zack Corr <zack@z0w0.me>
|
||||||
|
zofrex <zofrex@gmail.com>
|
@ -367,4 +367,3 @@ their own copyright notices and license terms:
|
|||||||
has chosen for the collective work, enumerated at the top
|
has chosen for the collective work, enumerated at the top
|
||||||
of this file. The only difference is the retention of
|
of this file. The only difference is the retention of
|
||||||
copyright itself, held by the contributor.
|
copyright itself, held by the contributor.
|
||||||
|
|
||||||
|
105
Makefile.in
105
Makefile.in
@ -101,7 +101,7 @@ endif
|
|||||||
|
|
||||||
ifdef CFG_ENABLE_DEBUG
|
ifdef CFG_ENABLE_DEBUG
|
||||||
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
|
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
|
||||||
CFG_RUSTC_FLAGS +=
|
CFG_RUSTC_FLAGS += --cfg debug
|
||||||
CFG_GCCISH_CFLAGS += -DRUST_DEBUG
|
CFG_GCCISH_CFLAGS += -DRUST_DEBUG
|
||||||
else
|
else
|
||||||
CFG_GCCISH_CFLAGS += -DRUST_NDEBUG
|
CFG_GCCISH_CFLAGS += -DRUST_NDEBUG
|
||||||
@ -110,6 +110,9 @@ endif
|
|||||||
ifdef SAVE_TEMPS
|
ifdef SAVE_TEMPS
|
||||||
CFG_RUSTC_FLAGS += --save-temps
|
CFG_RUSTC_FLAGS += --save-temps
|
||||||
endif
|
endif
|
||||||
|
ifdef ASM_COMMENTS
|
||||||
|
CFG_RUSTC_FLAGS += -Z asm-comments
|
||||||
|
endif
|
||||||
ifdef TIME_PASSES
|
ifdef TIME_PASSES
|
||||||
CFG_RUSTC_FLAGS += -Z time-passes
|
CFG_RUSTC_FLAGS += -Z time-passes
|
||||||
endif
|
endif
|
||||||
@ -119,6 +122,10 @@ endif
|
|||||||
ifdef TRACE
|
ifdef TRACE
|
||||||
CFG_RUSTC_FLAGS += -Z trace
|
CFG_RUSTC_FLAGS += -Z trace
|
||||||
endif
|
endif
|
||||||
|
ifndef DEBUG_BORROWS
|
||||||
|
RUSTFLAGS_STAGE1 += -Z no-debug-borrows
|
||||||
|
RUSTFLAGS_STAGE2 += -Z no-debug-borrows
|
||||||
|
endif
|
||||||
|
|
||||||
# platform-specific auto-configuration
|
# platform-specific auto-configuration
|
||||||
include $(CFG_SRC_DIR)mk/platform.mk
|
include $(CFG_SRC_DIR)mk/platform.mk
|
||||||
@ -132,15 +139,17 @@ endif
|
|||||||
|
|
||||||
# version-string calculation
|
# version-string calculation
|
||||||
CFG_GIT_DIR := $(CFG_SRC_DIR).git
|
CFG_GIT_DIR := $(CFG_SRC_DIR).git
|
||||||
CFG_RELEASE = 0.6
|
CFG_RELEASE = 0.7
|
||||||
CFG_VERSION = $(CFG_RELEASE)
|
CFG_VERSION = $(CFG_RELEASE)
|
||||||
|
# windows exe's need numeric versions - don't use anything but
|
||||||
|
# numbers and dots here
|
||||||
|
CFG_VERSION_WIN = 0.7
|
||||||
|
|
||||||
ifneq ($(wildcard $(CFG_GIT)),)
|
ifneq ($(wildcard $(CFG_GIT)),)
|
||||||
ifneq ($(wildcard $(CFG_GIT_DIR)),)
|
ifneq ($(wildcard $(CFG_GIT_DIR)),)
|
||||||
CFG_VERSION += $(shell git --git-dir=$(CFG_GIT_DIR) log -1 \
|
CFG_VERSION += $(shell git --git-dir=$(CFG_GIT_DIR) log -1 \
|
||||||
--pretty=format:'(%h %ci)')
|
--pretty=format:'(%h %ci)')
|
||||||
CFG_VER_HASH = $(shell git --git-dir=$(CFG_GIT_DIR) log -1 \
|
CFG_VER_HASH = $(shell git --git-dir=$(CFG_GIT_DIR) rev-parse HEAD)
|
||||||
--pretty=format:'%H')
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -198,30 +207,27 @@ define DEF_LIBS
|
|||||||
|
|
||||||
CFG_RUNTIME_$(1) :=$(call CFG_LIB_NAME_$(1),rustrt)
|
CFG_RUNTIME_$(1) :=$(call CFG_LIB_NAME_$(1),rustrt)
|
||||||
CFG_RUSTLLVM_$(1) :=$(call CFG_LIB_NAME_$(1),rustllvm)
|
CFG_RUSTLLVM_$(1) :=$(call CFG_LIB_NAME_$(1),rustllvm)
|
||||||
CFG_CORELIB_$(1) :=$(call CFG_LIB_NAME_$(1),core)
|
|
||||||
CFG_STDLIB_$(1) :=$(call CFG_LIB_NAME_$(1),std)
|
CFG_STDLIB_$(1) :=$(call CFG_LIB_NAME_$(1),std)
|
||||||
|
CFG_EXTRALIB_$(1) :=$(call CFG_LIB_NAME_$(1),extra)
|
||||||
CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
|
CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
|
||||||
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
|
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
|
||||||
CFG_LIBFUZZER_$(1) :=$(call CFG_LIB_NAME_$(1),fuzzer)
|
|
||||||
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
|
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
|
||||||
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
|
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
|
||||||
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
|
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
|
||||||
CFG_LIBRUST_$(1) :=$(call CFG_LIB_NAME_$(1),rust)
|
CFG_LIBRUST_$(1) :=$(call CFG_LIB_NAME_$(1),rust)
|
||||||
|
|
||||||
|
EXTRALIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),extra)
|
||||||
STDLIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),std)
|
STDLIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),std)
|
||||||
CORELIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),core)
|
|
||||||
LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
|
LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
|
||||||
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
|
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
|
||||||
LIBFUZZER_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),fuzzer)
|
|
||||||
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
|
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
|
||||||
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
|
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
|
||||||
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
|
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
|
||||||
LIBRUST_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rust)
|
LIBRUST_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rust)
|
||||||
|
EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
|
||||||
STDLIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),std)
|
STDLIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),std)
|
||||||
CORELIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),core)
|
|
||||||
LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
|
LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
|
||||||
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
|
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
|
||||||
LIBFUZZER_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),fuzzer)
|
|
||||||
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
|
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
|
||||||
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
|
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
|
||||||
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
|
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
|
||||||
@ -232,33 +238,33 @@ endef
|
|||||||
$(foreach target,$(CFG_TARGET_TRIPLES),\
|
$(foreach target,$(CFG_TARGET_TRIPLES),\
|
||||||
$(eval $(call DEF_LIBS,$(target))))
|
$(eval $(call DEF_LIBS,$(target))))
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# Core library variables
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
CORELIB_CRATE := $(S)src/libcore/core.rc
|
|
||||||
CORELIB_INPUTS := $(wildcard $(addprefix $(S)src/libcore/, \
|
|
||||||
core.rc *.rs */*.rs */*/*rs))
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Standard library variables
|
# Standard library variables
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
STDLIB_CRATE := $(S)src/libstd/std.rc
|
STDLIB_CRATE := $(S)src/libstd/std.rs
|
||||||
STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \
|
STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \
|
||||||
std.rc *.rs */*.rs))
|
*.rs */*.rs */*/*rs */*/*/*rs))
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Extra library variables
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
EXTRALIB_CRATE := $(S)src/libextra/extra.rs
|
||||||
|
EXTRALIB_INPUTS := $(wildcard $(addprefix $(S)src/libextra/, \
|
||||||
|
*.rs */*.rs))
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# rustc crate variables
|
# rustc crate variables
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
COMPILER_CRATE := $(S)src/librustc/rustc.rc
|
COMPILER_CRATE := $(S)src/librustc/rustc.rs
|
||||||
COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \
|
COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \
|
||||||
rustc.rc *.rs */*.rs */*/*.rs */*/*/*.rs))
|
*.rs */*.rs */*/*.rs */*/*/*.rs))
|
||||||
|
|
||||||
LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rc
|
LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs
|
||||||
LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
|
LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
|
||||||
syntax.rc *.rs */*.rs */*/*.rs))
|
*.rs */*.rs */*/*.rs))
|
||||||
|
|
||||||
DRIVER_CRATE := $(S)src/driver/driver.rs
|
DRIVER_CRATE := $(S)src/driver/driver.rs
|
||||||
|
|
||||||
@ -268,7 +274,7 @@ DRIVER_CRATE := $(S)src/driver/driver.rs
|
|||||||
|
|
||||||
# FIXME: x86-ism
|
# FIXME: x86-ism
|
||||||
LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit \
|
LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit \
|
||||||
interpreter
|
interpreter instrumentation
|
||||||
|
|
||||||
define DEF_LLVM_VARS
|
define DEF_LLVM_VARS
|
||||||
# The configure script defines these variables with the target triples
|
# The configure script defines these variables with the target triples
|
||||||
@ -308,6 +314,7 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
|
|||||||
export CFG_SRC_DIR
|
export CFG_SRC_DIR
|
||||||
export CFG_BUILD_DIR
|
export CFG_BUILD_DIR
|
||||||
export CFG_VERSION
|
export CFG_VERSION
|
||||||
|
export CFG_VERSION_WIN
|
||||||
export CFG_BUILD_TRIPLE
|
export CFG_BUILD_TRIPLE
|
||||||
export CFG_LLVM_ROOT
|
export CFG_LLVM_ROOT
|
||||||
export CFG_ENABLE_MINGW_CROSS
|
export CFG_ENABLE_MINGW_CROSS
|
||||||
@ -337,33 +344,33 @@ TROOT$(1)_T_$(2)_H_$(3) = $$(HLIB$(1)_H_$(3))/rustc/$(2)
|
|||||||
TBIN$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/bin
|
TBIN$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/bin
|
||||||
TLIB$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/$$(CFG_LIBDIR)
|
TLIB$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/$$(CFG_LIBDIR)
|
||||||
|
|
||||||
# The name of the core and standard libraries used by rustc
|
# The name of the standard and extra libraries used by rustc
|
||||||
ifdef CFG_DISABLE_SHAREDSTD
|
ifdef CFG_DISABLE_SHAREDSTD
|
||||||
HCORELIB_DEFAULT$(1)_H_$(3) = \
|
|
||||||
$$(HLIB$(1)_H_$(3))/libcore.rlib
|
|
||||||
TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libcore.rlib
|
|
||||||
|
|
||||||
HSTDLIB_DEFAULT$(1)_H_$(3) = \
|
HSTDLIB_DEFAULT$(1)_H_$(3) = \
|
||||||
$$(HLIB$(1)_H_$(3))/libstd.rlib
|
$$(HLIB$(1)_H_$(3))/libstd.rlib
|
||||||
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
|
$$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
|
||||||
|
|
||||||
|
HEXTRALIB_DEFAULT$(1)_H_$(3) = \
|
||||||
|
$$(HLIB$(1)_H_$(3))/libextra.rlib
|
||||||
|
TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/libextra.rlib
|
||||||
|
|
||||||
HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
|
HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
|
||||||
$$(HLIB$(1)_H_$(3))/librustc.rlib
|
$$(HLIB$(1)_H_$(3))/librustc.rlib
|
||||||
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/librustc.rlib
|
$$(TLIB$(1)_T_$(2)_H_$(3))/librustc.rlib
|
||||||
else
|
else
|
||||||
HCORELIB_DEFAULT$(1)_H_$(3) = \
|
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_CORELIB_$(3))
|
|
||||||
TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2))
|
|
||||||
|
|
||||||
HSTDLIB_DEFAULT$(1)_H_$(3) = \
|
HSTDLIB_DEFAULT$(1)_H_$(3) = \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
|
$$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
|
||||||
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
||||||
|
|
||||||
|
HEXTRALIB_DEFAULT$(1)_H_$(3) = \
|
||||||
|
$$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3))
|
||||||
|
TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
|
||||||
|
|
||||||
HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
|
HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
|
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
|
||||||
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
|
||||||
@ -375,8 +382,8 @@ HSREQ$(1)_H_$(3) = \
|
|||||||
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_RUNTIME_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_RUNTIME_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
|
||||||
$$(HCORELIB_DEFAULT$(1)_H_$(3)) \
|
|
||||||
$$(HSTDLIB_DEFAULT$(1)_H_$(3)) \
|
$$(HSTDLIB_DEFAULT$(1)_H_$(3)) \
|
||||||
|
$$(HEXTRALIB_DEFAULT$(1)_H_$(3)) \
|
||||||
$$(HLIBSYNTAX_DEFAULT$(1)_H_$(3)) \
|
$$(HLIBSYNTAX_DEFAULT$(1)_H_$(3)) \
|
||||||
$$(HLIBRUSTC_DEFAULT$(1)_H_$(3)) \
|
$$(HLIBRUSTC_DEFAULT$(1)_H_$(3)) \
|
||||||
$$(MKFILE_DEPS)
|
$$(MKFILE_DEPS)
|
||||||
@ -390,27 +397,24 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
|
|||||||
# Prerequisites for a working stageN compiler and libraries, for a specific target
|
# Prerequisites for a working stageN compiler and libraries, for a specific target
|
||||||
SREQ$(1)_T_$(2)_H_$(3) = \
|
SREQ$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
|
||||||
|
|
||||||
# Prerequisites for a working stageN compiler and libraries, for a specific target
|
# Prerequisites for a working stageN compiler and libraries, for a specific target
|
||||||
CSREQ$(1)_T_$(2)_H_$(3) = \
|
CSREQ$(1)_T_$(2)_H_$(3) = \
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(HBIN$(1)_H_$(3))/fuzzer$$(X_$(3)) \
|
|
||||||
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
|
||||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||||
$$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
|
||||||
$$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
|
$$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBFUZZER_$(3)) \
|
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(3)) \
|
||||||
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUST_$(3)) \
|
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUST_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBFUZZER_$(2)) \
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2)) \
|
||||||
@ -536,10 +540,19 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET_TRIPLES), \
|
|||||||
$(foreach host,$(CFG_HOST_TRIPLES), \
|
$(foreach host,$(CFG_HOST_TRIPLES), \
|
||||||
all-target-$(target)-host-$(host)))
|
all-target-$(target)-host-$(host)))
|
||||||
|
|
||||||
all: $(ALL_TARGET_RULES) $(GENERATED) docs
|
all: rustllvm/llvm-auto-clean-stamp \
|
||||||
|
$(ALL_TARGET_RULES) $(GENERATED) docs
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# This is used to independently force an LLVM clean rebuild
|
||||||
|
# when we changed something not otherwise captured by builtin
|
||||||
|
# dependencies. In these cases, commit a change that touches
|
||||||
|
# the stamp in the source dir.
|
||||||
|
rustllvm/llvm-auto-clean-stamp: $(S)src/rustllvm/llvm-auto-clean-trigger
|
||||||
|
$(Q)$(MAKE) clean-llvm
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Re-configuration
|
# Re-configuration
|
||||||
|
10
README.md
10
README.md
@ -42,9 +42,9 @@ packages:
|
|||||||
Assuming you're on a relatively modern *nix system and have met the
|
Assuming you're on a relatively modern *nix system and have met the
|
||||||
prerequisites, something along these lines should work.
|
prerequisites, something along these lines should work.
|
||||||
|
|
||||||
$ curl -O http://static.rust-lang.org/dist/rust-0.6.tar.gz
|
$ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
|
||||||
$ tar -xzf rust-0.6.tar.gz
|
$ tar -xzf rust-0.7.tar.gz
|
||||||
$ cd rust-0.6
|
$ cd rust-0.7
|
||||||
$ ./configure
|
$ ./configure
|
||||||
$ make && make install
|
$ make && make install
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ When complete, `make install` will place several programs into
|
|||||||
API-documentation tool, and `rustpkg`, the Rust package manager and build system.
|
API-documentation tool, and `rustpkg`, the Rust package manager and build system.
|
||||||
|
|
||||||
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
|
||||||
[tarball]: http://static.rust-lang.org/dist/rust-0.6.tar.gz
|
[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
|
||||||
[win-exe]: http://static.rust-lang.org/dist/rust-0.6-install.exe
|
[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
98
configure
vendored
98
configure
vendored
@ -138,7 +138,7 @@ validate_opt () {
|
|||||||
done
|
done
|
||||||
if [ "$arg" = "--help" ]
|
if [ "$arg" = "--help" ]
|
||||||
then
|
then
|
||||||
echo ""
|
echo
|
||||||
echo "No more help available for Configure options,"
|
echo "No more help available for Configure options,"
|
||||||
echo "check the Wiki or join our IRC channel"
|
echo "check the Wiki or join our IRC channel"
|
||||||
break
|
break
|
||||||
@ -237,7 +237,7 @@ need_cmd uname
|
|||||||
need_cmd date
|
need_cmd date
|
||||||
need_cmd tr
|
need_cmd tr
|
||||||
need_cmd sed
|
need_cmd sed
|
||||||
|
need_cmd file
|
||||||
|
|
||||||
msg "inspecting environment"
|
msg "inspecting environment"
|
||||||
|
|
||||||
@ -349,11 +349,11 @@ if [ "$1" = "--help" ]
|
|||||||
then
|
then
|
||||||
HELP=1
|
HELP=1
|
||||||
shift
|
shift
|
||||||
echo ""
|
echo
|
||||||
echo "Usage: $CFG_SELF [options]"
|
echo "Usage: $CFG_SELF [options]"
|
||||||
echo ""
|
echo
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo ""
|
echo
|
||||||
else
|
else
|
||||||
msg "recreating config.tmp"
|
msg "recreating config.tmp"
|
||||||
echo '' >config.tmp
|
echo '' >config.tmp
|
||||||
@ -376,6 +376,7 @@ opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
|
|||||||
opt manage-submodules 1 "let the build manage the git submodules"
|
opt manage-submodules 1 "let the build manage the git submodules"
|
||||||
opt mingw-cross 0 "cross-compile for win32 using mingw"
|
opt mingw-cross 0 "cross-compile for win32 using mingw"
|
||||||
opt clang 0 "prefer clang to gcc for building the runtime"
|
opt clang 0 "prefer clang to gcc for building the runtime"
|
||||||
|
opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
|
||||||
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
|
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
|
||||||
opt pax-flags 0 "apply PaX flags to rustc binaries (required for GRSecurity/PaX-patched kernels)"
|
opt pax-flags 0 "apply PaX flags to rustc binaries (required for GRSecurity/PaX-patched kernels)"
|
||||||
valopt prefix "/usr/local" "set installation prefix"
|
valopt prefix "/usr/local" "set installation prefix"
|
||||||
@ -393,7 +394,7 @@ validate_opt
|
|||||||
|
|
||||||
if [ $HELP -eq 1 ]
|
if [ $HELP -eq 1 ]
|
||||||
then
|
then
|
||||||
echo ""
|
echo
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -421,6 +422,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
probe CFG_CLANG clang++
|
probe CFG_CLANG clang++
|
||||||
|
probe CFG_CCACHE ccache
|
||||||
probe CFG_GCC gcc
|
probe CFG_GCC gcc
|
||||||
probe CFG_LD ld
|
probe CFG_LD ld
|
||||||
probe CFG_VALGRIND valgrind
|
probe CFG_VALGRIND valgrind
|
||||||
@ -439,6 +441,10 @@ then
|
|||||||
probe CFG_ZCAT zcat
|
probe CFG_ZCAT zcat
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
step_msg "looking for target specific programs"
|
||||||
|
|
||||||
|
probe CFG_ADB adb
|
||||||
|
|
||||||
if [ ! -z "$CFG_PANDOC" ]
|
if [ ! -z "$CFG_PANDOC" ]
|
||||||
then
|
then
|
||||||
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc ' |
|
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc ' |
|
||||||
@ -533,7 +539,7 @@ then
|
|||||||
LLVM_VERSION=$($LLVM_CONFIG --version)
|
LLVM_VERSION=$($LLVM_CONFIG --version)
|
||||||
|
|
||||||
case $LLVM_VERSION in
|
case $LLVM_VERSION in
|
||||||
(3.2svn|3.2|3.1svn|3.1|3.0svn|3.0)
|
(3.3|3.3svn|3.2|3.2svn)
|
||||||
msg "found ok version of LLVM: $LLVM_VERSION"
|
msg "found ok version of LLVM: $LLVM_VERSION"
|
||||||
;;
|
;;
|
||||||
(*)
|
(*)
|
||||||
@ -551,11 +557,11 @@ then
|
|||||||
CFG_CLANG_VERSION=$("$CFG_CLANG" \
|
CFG_CLANG_VERSION=$("$CFG_CLANG" \
|
||||||
--version \
|
--version \
|
||||||
| grep version \
|
| grep version \
|
||||||
| sed 's/.*\(version .*\)/\1/' \
|
| sed 's/.*\(version .*\)/\1/; s/.*based on \(LLVM .*\))/\1/' \
|
||||||
| cut -d ' ' -f 2)
|
| cut -d ' ' -f 2)
|
||||||
|
|
||||||
case $CFG_CLANG_VERSION in
|
case $CFG_CLANG_VERSION in
|
||||||
(3.0svn | 3.0 | 3.1* | 3.2* | 3.3* | 4.0* | 4.1* | 4.2*)
|
(3.0svn | 3.0 | 3.1* | 3.2* | 3.3* | 3.4* )
|
||||||
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
|
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
|
||||||
CFG_C_COMPILER="clang"
|
CFG_C_COMPILER="clang"
|
||||||
;;
|
;;
|
||||||
@ -567,6 +573,16 @@ else
|
|||||||
CFG_C_COMPILER="gcc"
|
CFG_C_COMPILER="gcc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$CFG_ENABLE_CCACHE" ]
|
||||||
|
then
|
||||||
|
if [ -z "$CFG_CCACHE" ]
|
||||||
|
then
|
||||||
|
err "ccache requested but not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CFG_C_COMPILER="ccache $CFG_C_COMPILER"
|
||||||
|
fi
|
||||||
|
|
||||||
# a little post-processing of various config values
|
# a little post-processing of various config values
|
||||||
|
|
||||||
CFG_PREFIX=${CFG_PREFIX%/}
|
CFG_PREFIX=${CFG_PREFIX%/}
|
||||||
@ -639,7 +655,7 @@ fi
|
|||||||
step_msg "making directories"
|
step_msg "making directories"
|
||||||
|
|
||||||
for i in \
|
for i in \
|
||||||
doc doc/core doc/std \
|
doc doc/std doc/extra \
|
||||||
dl tmp
|
dl tmp
|
||||||
do
|
do
|
||||||
make_dir $i
|
make_dir $i
|
||||||
@ -661,12 +677,17 @@ make_dir rt
|
|||||||
for t in $CFG_TARGET_TRIPLES
|
for t in $CFG_TARGET_TRIPLES
|
||||||
do
|
do
|
||||||
make_dir rt/$t
|
make_dir rt/$t
|
||||||
for i in \
|
for s in 0 1 2 3
|
||||||
isaac linenoise sync test \
|
|
||||||
arch/i386 arch/x86_64 arch/arm arch/mips \
|
|
||||||
libuv libuv/src/ares libuv/src/eio libuv/src/ev
|
|
||||||
do
|
do
|
||||||
make_dir rt/$t/$i
|
make_dir rt/$t/stage$s
|
||||||
|
for i in \
|
||||||
|
isaac linenoise sync test \
|
||||||
|
arch/i386 arch/x86_64 arch/arm arch/mips \
|
||||||
|
libuv libuv/src/ares libuv/src/eio libuv/src/ev \
|
||||||
|
jemalloc
|
||||||
|
do
|
||||||
|
make_dir rt/$t/stage$s/$i
|
||||||
|
done
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -691,6 +712,9 @@ do
|
|||||||
# host lib dir
|
# host lib dir
|
||||||
make_dir $h/stage$i/$CFG_LIBDIR
|
make_dir $h/stage$i/$CFG_LIBDIR
|
||||||
|
|
||||||
|
# host test dir
|
||||||
|
make_dir $h/stage$i/test
|
||||||
|
|
||||||
# target bin dir
|
# target bin dir
|
||||||
make_dir $h/stage$i/$CFG_LIBDIR/rustc/$t/bin
|
make_dir $h/stage$i/$CFG_LIBDIR/rustc/$t/bin
|
||||||
|
|
||||||
@ -810,24 +834,37 @@ do
|
|||||||
LLVM_TARGET="--target=$t"
|
LLVM_TARGET="--target=$t"
|
||||||
|
|
||||||
# Disable unused LLVM features
|
# Disable unused LLVM features
|
||||||
LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs \
|
LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs --enable-bindings=none"
|
||||||
--enable-bindings=none --disable-threads \
|
|
||||||
--disable-pthreads"
|
|
||||||
|
|
||||||
if [ "$CFG_C_COMPILER" = "clang" ]
|
case "$CFG_C_COMPILER" in
|
||||||
then
|
("ccache clang")
|
||||||
|
LLVM_CXX_32="ccache clang++ -m32 -Qunused-arguments"
|
||||||
|
LLVM_CC_32="ccache clang -m32 -Qunused-arguments"
|
||||||
|
|
||||||
|
LLVM_CXX_64="ccache clang++ -Qunused-arguments"
|
||||||
|
LLVM_CC_64="ccache clang -Qunused-arguments"
|
||||||
|
;;
|
||||||
|
("clang")
|
||||||
LLVM_CXX_32="clang++ -m32"
|
LLVM_CXX_32="clang++ -m32"
|
||||||
LLVM_CC_32="clang -m32"
|
LLVM_CC_32="clang -m32"
|
||||||
|
|
||||||
LLVM_CXX_64="clang++"
|
LLVM_CXX_64="clang++"
|
||||||
LLVM_CC_64="clang"
|
LLVM_CC_64="clang"
|
||||||
else
|
;;
|
||||||
|
("ccache gcc")
|
||||||
|
LLVM_CXX_32="ccache g++ -m32"
|
||||||
|
LLVM_CC_32="ccache gcc -m32"
|
||||||
|
|
||||||
|
LLVM_CXX_64="ccache g++"
|
||||||
|
LLVM_CC_64="ccache gcc"
|
||||||
|
;;
|
||||||
|
("gcc")
|
||||||
LLVM_CXX_32="g++ -m32"
|
LLVM_CXX_32="g++ -m32"
|
||||||
LLVM_CC_32="gcc -m32"
|
LLVM_CC_32="gcc -m32"
|
||||||
|
|
||||||
LLVM_CXX_64="g++"
|
LLVM_CXX_64="g++"
|
||||||
LLVM_CC_64="gcc"
|
LLVM_CC_64="gcc"
|
||||||
fi
|
esac
|
||||||
|
|
||||||
LLVM_CFLAGS_32="-m32"
|
LLVM_CFLAGS_32="-m32"
|
||||||
LLVM_CXXFLAGS_32="-m32"
|
LLVM_CXXFLAGS_32="-m32"
|
||||||
@ -859,7 +896,7 @@ do
|
|||||||
LDFLAGS=$LLVM_LDFLAGS
|
LDFLAGS=$LLVM_LDFLAGS
|
||||||
|
|
||||||
LLVM_FLAGS="$LLVM_TARGETS $LLVM_OPTS $LLVM_BUILD \
|
LLVM_FLAGS="$LLVM_TARGETS $LLVM_OPTS $LLVM_BUILD \
|
||||||
$LLVM_HOST $LLVM_TARGET"
|
$LLVM_HOST $LLVM_TARGET --with-python=$CFG_PYTHON"
|
||||||
|
|
||||||
msg "configuring LLVM with:"
|
msg "configuring LLVM with:"
|
||||||
msg "$LLVM_FLAGS"
|
msg "$LLVM_FLAGS"
|
||||||
@ -924,6 +961,21 @@ then
|
|||||||
putvar CFG_PAXCTL
|
putvar CFG_PAXCTL
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Avoid spurious warnings from clang by feeding it original source on
|
||||||
|
# ccache-miss rather than preprocessed input.
|
||||||
|
if [ ! -z "$CFG_ENABLE_CCACHE" ] && [ ! -z "$CFG_ENABLE_CLANG" ]
|
||||||
|
then
|
||||||
|
CFG_CCACHE_CPP2=1
|
||||||
|
putvar CFG_CCACHE_CPP2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$CFG_ENABLE_CCACHE" ]
|
||||||
|
then
|
||||||
|
CFG_CCACHE_BASEDIR=${CFG_SRC_DIR}
|
||||||
|
putvar CFG_CCACHE_BASEDIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ ! -z $BAD_PANDOC ]
|
if [ ! -z $BAD_PANDOC ]
|
||||||
then
|
then
|
||||||
CFG_PANDOC=
|
CFG_PANDOC=
|
||||||
|
29
doc/README
29
doc/README
@ -1,13 +1,28 @@
|
|||||||
The markdown docs are only generated by make when node is installed (use
|
Pandoc, a universal document converter, is required to generate docs as HTML
|
||||||
`make doc`). If you don't have node installed you can generate them yourself.
|
from Rust's source code. It's available for most platforms here:
|
||||||
Unfortunately there's no real standard for markdown and all the tools work
|
http://johnmacfarlane.net/pandoc/installing.html
|
||||||
differently. pandoc is one that seems to work well.
|
|
||||||
|
|
||||||
To generate an html version of a doc do something like:
|
Node.js (http://nodejs.org/) is also required for generating HTML from
|
||||||
pandoc --from=markdown --to=html --number-sections -o build/doc/rust.html doc/rust.md && git web--browse build/doc/rust.html
|
the Markdown docs (reference manual, tutorials, etc.) distributed with
|
||||||
|
this git repository.
|
||||||
|
|
||||||
|
To generate all the docs, run `make docs` from the root of the repository.
|
||||||
|
This will convert the distributed Markdown docs to HTML and generate HTML doc
|
||||||
|
for the 'std' and 'extra' libraries.
|
||||||
|
|
||||||
|
To generate HTML documentation from one source file/crate, do something like:
|
||||||
|
|
||||||
|
rustdoc --output-dir html-doc/ --output-format html ../src/libstd/path.rs
|
||||||
|
|
||||||
|
(This, of course, requires that you've built/installed the `rustdoc` tool.)
|
||||||
|
|
||||||
|
To generate an HTML version of a doc from Markdown, without having Node.js
|
||||||
|
installed, do something like:
|
||||||
|
|
||||||
|
pandoc --from=markdown --to=html --number-sections -o rust.html rust.md
|
||||||
|
|
||||||
The syntax for pandoc flavored markdown can be found at:
|
The syntax for pandoc flavored markdown can be found at:
|
||||||
http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown
|
http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown
|
||||||
|
|
||||||
A nice quick reference (for non-pandoc markdown) is at:
|
A nice quick reference (for non-pandoc markdown) is at:
|
||||||
http://kramdown.rubyforge.org/quickref.html
|
http://kramdown.rubyforge.org/quickref.html
|
||||||
|
97
doc/rust.css
97
doc/rust.css
@ -1,39 +1,78 @@
|
|||||||
body {
|
body {
|
||||||
padding: 1em;
|
padding: 1em 6em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-bottom: 4em;
|
margin-bottom: 4em;
|
||||||
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
||||||
background-color: white;
|
font-size: 12pt;
|
||||||
color: black;
|
background-color: white;
|
||||||
line-height: 1.6em;
|
color: black;
|
||||||
}
|
line-height: 1.6em;
|
||||||
|
min-width: 45em;
|
||||||
body {
|
max-width: 60em;
|
||||||
padding: 1em 6em;
|
|
||||||
max-width: 60em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 20pt;
|
font-size: 24pt;
|
||||||
margin-top: 2em;
|
margin-top: 1.6em;
|
||||||
border-bottom: 1px solid silver;
|
padding-left: 0.4em;
|
||||||
line-height: 1.6em;
|
line-height: 1.6em;
|
||||||
|
background-color:#FFF2CE;
|
||||||
|
border-radius: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 15pt;
|
font-size: 16pt;
|
||||||
margin-top: 2em;
|
margin-top: 1.6em;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
background-color:#FFF2CE;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 code {
|
||||||
|
color: #097334;
|
||||||
|
font-size: 16pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 14pt;
|
||||||
|
color: black;
|
||||||
|
background-color:#D9E7FF;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 code {
|
||||||
|
color: #541800;
|
||||||
|
font-size: 14pt;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 11pt;
|
||||||
|
margin-top: 0em;
|
||||||
|
margin-bottom: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 11pt;
|
||||||
}
|
}
|
||||||
h3 { font-size: 13pt; }
|
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
margin: 1.1em 0;
|
margin-left: 1.1em;
|
||||||
padding: .4em .4em .4em 2em;
|
padding: .4em .4em .4em .8em;
|
||||||
font-size: 120%;
|
font-size: 10pt;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.rust {
|
||||||
|
background-color: #F3F6FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
a, a:visited, a:link {
|
a, a:visited, a:link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: rgb(0, 105, 214);
|
color: rgb(0, 105, 214);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 a:link, h1 a:visited, h2 a:link, h2 a:visited,
|
h1 a:link, h1 a:visited, h2 a:link, h2 a:visited,
|
||||||
@ -106,4 +145,12 @@ td {
|
|||||||
/* Adjust list alignment so rustdoc indexes don't align with blockquotes */
|
/* Adjust list alignment so rustdoc indexes don't align with blockquotes */
|
||||||
div.index ul {
|
div.index ul {
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-top: 0em
|
||||||
|
}
|
||||||
|
|
||||||
|
div.section.level3 {
|
||||||
|
margin-left: 1.0em;
|
||||||
|
}
|
||||||
|
365
doc/rust.md
365
doc/rust.md
@ -17,14 +17,14 @@ This document does not serve as a tutorial introduction to the
|
|||||||
language. Background familiarity with the language is assumed. A separate
|
language. Background familiarity with the language is assumed. A separate
|
||||||
[tutorial] document is available to help acquire such background familiarity.
|
[tutorial] document is available to help acquire such background familiarity.
|
||||||
|
|
||||||
This document also does not serve as a reference to the [core] or [standard]
|
This document also does not serve as a reference to the [standard] or [extra]
|
||||||
libraries included in the language distribution. Those libraries are
|
libraries included in the language distribution. Those libraries are
|
||||||
documented separately by extracting documentation attributes from their
|
documented separately by extracting documentation attributes from their
|
||||||
source code.
|
source code.
|
||||||
|
|
||||||
[tutorial]: tutorial.html
|
[tutorial]: tutorial.html
|
||||||
[core]: core/index.html
|
|
||||||
[standard]: std/index.html
|
[standard]: std/index.html
|
||||||
|
[extra]: extra/index.html
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
@ -301,10 +301,10 @@ num_lit : nonzero_dec [ dec_digit | '_' ] * num_suffix ?
|
|||||||
num_suffix : int_suffix | float_suffix ;
|
num_suffix : int_suffix | float_suffix ;
|
||||||
|
|
||||||
int_suffix : 'u' int_suffix_size ?
|
int_suffix : 'u' int_suffix_size ?
|
||||||
| 'i' int_suffix_size ;
|
| 'i' int_suffix_size ? ;
|
||||||
int_suffix_size : [ '8' | '1' '6' | '3' '2' | '6' '4' ] ;
|
int_suffix_size : [ '8' | '1' '6' | '3' '2' | '6' '4' ] ;
|
||||||
|
|
||||||
float_suffix : [ exponent | '.' dec_lit exponent ? ] float_suffix_ty ? ;
|
float_suffix : [ exponent | '.' dec_lit exponent ? ] ? float_suffix_ty ? ;
|
||||||
float_suffix_ty : 'f' [ '3' '2' | '6' '4' ] ;
|
float_suffix_ty : 'f' [ '3' '2' | '6' '4' ] ;
|
||||||
exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
|
exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
|
||||||
dec_lit : [ dec_digit | '_' ] + ;
|
dec_lit : [ dec_digit | '_' ] + ;
|
||||||
@ -441,10 +441,10 @@ expression context, the final namespace qualifier is omitted.
|
|||||||
Two examples of paths with type arguments:
|
Two examples of paths with type arguments:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::hashmap::linear::LinearMap;
|
# use std::hashmap::HashMap;
|
||||||
# fn f() {
|
# fn f() {
|
||||||
# fn id<T:Copy>(t: T) -> T { t }
|
# fn id<T:Copy>(t: T) -> T { t }
|
||||||
type t = LinearMap<int,~str>; // Type arguments used in a type expression
|
type t = HashMap<int,~str>; // Type arguments used in a type expression
|
||||||
let x = id::<int>(10); // Type arguments used in a call expression
|
let x = id::<int>(10); // Type arguments used in a call expression
|
||||||
# }
|
# }
|
||||||
~~~~
|
~~~~
|
||||||
@ -618,7 +618,7 @@ each of which may have some number of [attributes](#attributes) attached to it.
|
|||||||
|
|
||||||
~~~~~~~~ {.ebnf .gram}
|
~~~~~~~~ {.ebnf .gram}
|
||||||
item : mod_item | fn_item | type_item | struct_item | enum_item
|
item : mod_item | fn_item | type_item | struct_item | enum_item
|
||||||
| static_item | trait_item | impl_item | foreign_mod_item ;
|
| static_item | trait_item | impl_item | extern_block ;
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
An _item_ is a component of a crate; some module items can be defined in crate
|
An _item_ is a component of a crate; some module items can be defined in crate
|
||||||
@ -752,10 +752,11 @@ link_attr : ident '=' literal ;
|
|||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
An _`extern mod` declaration_ specifies a dependency on an external crate.
|
An _`extern mod` declaration_ specifies a dependency on an external crate.
|
||||||
The external crate is then bound into the declaring scope as the `ident` provided in the `extern_mod_decl`.
|
The external crate is then bound into the declaring scope
|
||||||
|
as the `ident` provided in the `extern_mod_decl`.
|
||||||
|
|
||||||
The external crate is resolved to a specific `soname` at compile time, and a
|
The external crate is resolved to a specific `soname` at compile time,
|
||||||
runtime linkage requirement to that `soname` is passed to the linker for
|
and a runtime linkage requirement to that `soname` is passed to the linker for
|
||||||
loading at runtime. The `soname` is resolved at compile time by scanning the
|
loading at runtime. The `soname` is resolved at compile time by scanning the
|
||||||
compiler's library path and matching the `link_attrs` provided in the
|
compiler's library path and matching the `link_attrs` provided in the
|
||||||
`use_decl` against any `#link` attributes that were declared on the external
|
`use_decl` against any `#link` attributes that were declared on the external
|
||||||
@ -767,9 +768,9 @@ Three examples of `extern mod` declarations:
|
|||||||
~~~~~~~~{.xfail-test}
|
~~~~~~~~{.xfail-test}
|
||||||
extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841");
|
extern mod pcre (uuid = "54aba0f8-a7b1-4beb-92f1-4cf625264841");
|
||||||
|
|
||||||
extern mod std; // equivalent to: extern mod std ( name = "std" );
|
extern mod extra; // equivalent to: extern mod extra ( name = "extra" );
|
||||||
|
|
||||||
extern mod ruststd (name = "std"); // linking to 'std' under another name
|
extern mod rustextra (name = "extra"); // linking to 'extra' under another name
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
##### Use declarations
|
##### Use declarations
|
||||||
@ -801,20 +802,15 @@ Use declarations support a number of convenient shortcuts:
|
|||||||
An example of `use` declarations:
|
An example of `use` declarations:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
use core::float::sin;
|
use std::float::sin;
|
||||||
use core::str::{slice, to_upper};
|
use std::option::{Some, None};
|
||||||
use core::option::Some;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Equivalent to 'info!(core::float::sin(1.0));'
|
// Equivalent to 'info!(std::float::sin(1.0));'
|
||||||
info!(sin(1.0));
|
info!(sin(1.0));
|
||||||
|
|
||||||
// Equivalent to 'info!(core::option::Some(1.0));'
|
// Equivalent to 'info!(~[std::option::Some(1.0), std::option::None]);'
|
||||||
info!(Some(1.0));
|
info!(~[Some(1.0), None]);
|
||||||
|
|
||||||
// Equivalent to
|
|
||||||
// 'info!(core::str::to_upper(core::str::slice("foo", 0, 1)));'
|
|
||||||
info!(to_upper(slice("foo", 0, 1)));
|
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
@ -886,11 +882,11 @@ the function name.
|
|||||||
|
|
||||||
~~~~ {.xfail-test}
|
~~~~ {.xfail-test}
|
||||||
fn iter<T>(seq: &[T], f: &fn(T)) {
|
fn iter<T>(seq: &[T], f: &fn(T)) {
|
||||||
for seq.each |elt| { f(elt); }
|
for seq.iter().advance |elt| { f(elt); }
|
||||||
}
|
}
|
||||||
fn map<T, U>(seq: &[T], f: &fn(T) -> U) -> ~[U] {
|
fn map<T, U>(seq: &[T], f: &fn(T) -> U) -> ~[U] {
|
||||||
let mut acc = ~[];
|
let mut acc = ~[];
|
||||||
for seq.each |elt| { acc.push(f(elt)); }
|
for seq.iter().advance |elt| { acc.push(f(elt)); }
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
@ -992,10 +988,10 @@ Thus the return type on `f` only needs to reflect the `if` branch of the conditi
|
|||||||
#### Extern functions
|
#### Extern functions
|
||||||
|
|
||||||
Extern functions are part of Rust's foreign function interface,
|
Extern functions are part of Rust's foreign function interface,
|
||||||
providing the opposite functionality to [foreign modules](#foreign-modules).
|
providing the opposite functionality to [external blocks](#external-blocks).
|
||||||
Whereas foreign modules allow Rust code to call foreign code,
|
Whereas external blocks allow Rust code to call foreign code,
|
||||||
extern functions with bodies defined in Rust code _can be called by foreign code_.
|
extern functions with bodies defined in Rust code _can be called by foreign
|
||||||
They are defined in the same way as any other Rust function,
|
code_. They are defined in the same way as any other Rust function,
|
||||||
except that they have the `extern` modifier.
|
except that they have the `extern` modifier.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
@ -1011,7 +1007,8 @@ let fptr: *u8 = new_vec;
|
|||||||
~~~
|
~~~
|
||||||
|
|
||||||
The primary motivation for extern functions is
|
The primary motivation for extern functions is
|
||||||
to create callbacks for foreign functions that expect to receive function pointers.
|
to create callbacks for foreign functions that expect to receive function
|
||||||
|
pointers.
|
||||||
|
|
||||||
### Type definitions
|
### Type definitions
|
||||||
|
|
||||||
@ -1295,7 +1292,7 @@ with matching types and type parameter counts.
|
|||||||
|
|
||||||
An implementation can take type parameters,
|
An implementation can take type parameters,
|
||||||
which can be different from the type parameters taken by the trait it implements.
|
which can be different from the type parameters taken by the trait it implements.
|
||||||
Implementation parameters are written after after the `impl` keyword.
|
Implementation parameters are written after the `impl` keyword.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# trait Seq<T> { }
|
# trait Seq<T> { }
|
||||||
@ -1308,64 +1305,61 @@ impl Seq<bool> for u32 {
|
|||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### Foreign modules
|
### External blocks
|
||||||
|
|
||||||
~~~ {.ebnf .gram}
|
~~~ {.ebnf .gram}
|
||||||
foreign_mod_item : "extern mod" ident '{' foreign_mod '} ;
|
extern_block_item : "extern" '{' extern_block '} ;
|
||||||
foreign_mod : [ foreign_fn ] * ;
|
extern_block : [ foreign_fn ] * ;
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Foreign modules form the basis for Rust's foreign function interface. A
|
External blocks form the basis for Rust's foreign function interface.
|
||||||
foreign module describes functions in external, non-Rust
|
Declarations in an external block describe symbols
|
||||||
libraries.
|
in external, non-Rust libraries.
|
||||||
Functions within foreign modules are declared in the same way as other Rust functions,
|
|
||||||
with the exception that they may not have a body and are instead terminated by a semicolon.
|
Functions within external blocks
|
||||||
|
are declared in the same way as other Rust functions,
|
||||||
|
with the exception that they may not have a body
|
||||||
|
and are instead terminated by a semicolon.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::libc::{c_char, FILE};
|
# use std::libc::{c_char, FILE};
|
||||||
# #[nolink]
|
# #[nolink]
|
||||||
|
|
||||||
extern mod c {
|
extern {
|
||||||
fn fopen(filename: *c_char, mode: *c_char) -> *FILE;
|
fn fopen(filename: *c_char, mode: *c_char) -> *FILE;
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Functions within foreign modules may be called by Rust code, just like functions defined in Rust.
|
Functions within external blocks may be called by Rust code,
|
||||||
The Rust compiler automatically translates between the Rust ABI and the foreign ABI.
|
just like functions defined in Rust.
|
||||||
|
The Rust compiler automatically translates
|
||||||
|
between the Rust ABI and the foreign ABI.
|
||||||
|
|
||||||
The name of the foreign module has special meaning to the Rust compiler in
|
A number of [attributes](#attributes) control the behavior of external
|
||||||
that it will treat the module name as the name of a library to link to,
|
blocks.
|
||||||
performing the linking as appropriate for the target platform. The name
|
|
||||||
given for the foreign module will be transformed in a platform-specific way
|
|
||||||
to determine the name of the library. For example, on Linux the name of the
|
|
||||||
foreign module is prefixed with 'lib' and suffixed with '.so', so the
|
|
||||||
foreign mod 'rustrt' would be linked to a library named 'librustrt.so'.
|
|
||||||
|
|
||||||
A number of [attributes](#attributes) control the behavior of foreign
|
By default external blocks assume
|
||||||
modules.
|
that the library they are calling uses the standard C "cdecl" ABI.
|
||||||
|
Other ABIs may be specified using the `abi` attribute as in
|
||||||
By default foreign modules assume that the library they are calling use the
|
|
||||||
standard C "cdecl" ABI. Other ABIs may be specified using the `abi`
|
|
||||||
attribute as in
|
|
||||||
|
|
||||||
~~~{.xfail-test}
|
~~~{.xfail-test}
|
||||||
// Interface to the Windows API
|
// Interface to the Windows API
|
||||||
#[abi = "stdcall"]
|
#[abi = "stdcall"]
|
||||||
extern mod kernel32 { }
|
extern { }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The `link_name` attribute allows the default library naming behavior to
|
The `link_name` attribute allows the name of the library to be specified.
|
||||||
be overridden by explicitly specifying the name of the library.
|
|
||||||
|
|
||||||
~~~{.xfail-test}
|
~~~{.xfail-test}
|
||||||
#[link_name = "crypto"]
|
#[link_name = "crypto"]
|
||||||
extern mod mycrypto { }
|
extern { }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The `nolink` attribute tells the Rust compiler not to do any linking for the foreign module.
|
The `nolink` attribute tells the Rust compiler
|
||||||
This is particularly useful for creating foreign
|
not to do any linking for the external block.
|
||||||
modules for libc, which tends to not follow standard library naming
|
This is particularly useful for creating external blocks for libc,
|
||||||
conventions and is linked to all Rust programs anyway.
|
which tends to not follow standard library naming conventions
|
||||||
|
and is linked to all Rust programs anyway.
|
||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
@ -1425,6 +1419,9 @@ names are effectively reserved. Some significant attributes include:
|
|||||||
* The `test` attribute, for marking functions as unit tests.
|
* The `test` attribute, for marking functions as unit tests.
|
||||||
* The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint checks. Lint checks supported
|
* The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint checks. Lint checks supported
|
||||||
by the compiler can be found via `rustc -W help`.
|
by the compiler can be found via `rustc -W help`.
|
||||||
|
* The `deriving` attribute, for automatically generating
|
||||||
|
implementations of certain traits.
|
||||||
|
* The `static_assert` attribute, for asserting that a static bool is true at compiletime
|
||||||
|
|
||||||
Other attributes may be added or removed during development of the language.
|
Other attributes may be added or removed during development of the language.
|
||||||
|
|
||||||
@ -1434,7 +1431,7 @@ Some primitive Rust operations are defined in Rust code,
|
|||||||
rather than being implemented directly in C or assembly language.
|
rather than being implemented directly in C or assembly language.
|
||||||
The definitions of these operations have to be easy for the compiler to find.
|
The definitions of these operations have to be easy for the compiler to find.
|
||||||
The `lang` attribute makes it possible to declare these operations.
|
The `lang` attribute makes it possible to declare these operations.
|
||||||
For example, the `str` module in the Rust core library defines the string equality function:
|
For example, the `str` module in the Rust standard library defines the string equality function:
|
||||||
|
|
||||||
~~~ {.xfail-test}
|
~~~ {.xfail-test}
|
||||||
#[lang="str_eq"]
|
#[lang="str_eq"]
|
||||||
@ -1468,9 +1465,9 @@ A complete list of the built-in language items follows:
|
|||||||
`mul`
|
`mul`
|
||||||
: Elements can be multiplied.
|
: Elements can be multiplied.
|
||||||
`div`
|
`div`
|
||||||
: Elements can be divided.
|
: Elements have a division operation.
|
||||||
`mod`
|
`rem`
|
||||||
: Elements have a modulo operation.
|
: Elements have a remainder operation.
|
||||||
`neg`
|
`neg`
|
||||||
: Elements can be negated arithmetically.
|
: Elements can be negated arithmetically.
|
||||||
`not`
|
`not`
|
||||||
@ -1526,6 +1523,50 @@ A complete list of the built-in language items follows:
|
|||||||
> **Note:** This list is likely to become out of date. We should auto-generate it
|
> **Note:** This list is likely to become out of date. We should auto-generate it
|
||||||
> from `librustc/middle/lang_items.rs`.
|
> from `librustc/middle/lang_items.rs`.
|
||||||
|
|
||||||
|
### Deriving
|
||||||
|
|
||||||
|
The `deriving` attribute allows certain traits to be automatically
|
||||||
|
implemented for data structures. For example, the following will
|
||||||
|
create an `impl` for the `Eq` and `Clone` traits for `Foo`, the type
|
||||||
|
parameter `T` will be given the `Eq` or `Clone` constraints for the
|
||||||
|
appropriate `impl`:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
#[deriving(Eq, Clone)]
|
||||||
|
struct Foo<T> {
|
||||||
|
a: int,
|
||||||
|
b: T
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The generated `impl` for `Eq` is equivalent to
|
||||||
|
|
||||||
|
~~~
|
||||||
|
# struct Foo<T> { a: int, b: T }
|
||||||
|
impl<T: Eq> Eq for Foo<T> {
|
||||||
|
fn eq(&self, other: &Foo<T>) -> bool {
|
||||||
|
self.a == other.a && self.b == other.b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ne(&self, other: &Foo<T>) -> bool {
|
||||||
|
self.a != other.a || self.b != other.b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Supported traits for `deriving` are:
|
||||||
|
|
||||||
|
* Comparison traits: `Eq`, `TotalEq`, `Ord`, `TotalOrd`.
|
||||||
|
* Serialization: `Encodable`, `Decodable`. These require `extra`.
|
||||||
|
* `Clone` and `DeepClone`, to perform (deep) copies.
|
||||||
|
* `IterBytes`, to iterate over the bytes in a data type.
|
||||||
|
* `Rand`, to create a random instance of a data type.
|
||||||
|
* `Zero`, to create an zero (or empty) instance of a data type.
|
||||||
|
* `ToStr`, to convert to a string. For a type with this instance,
|
||||||
|
`obj.to_str()` has similar output as `fmt!("%?", obj)`, but it differs in that
|
||||||
|
each constituent field of the type must also implement `ToStr` and will have
|
||||||
|
`field.to_str()` invoked to build up the result.
|
||||||
|
|
||||||
# Statements and expressions
|
# Statements and expressions
|
||||||
|
|
||||||
Rust is _primarily_ an expression language. This means that most forms of
|
Rust is _primarily_ an expression language. This means that most forms of
|
||||||
@ -1653,11 +1694,12 @@ Path expressions are [lvalues](#lvalues-rvalues-and-temporaries).
|
|||||||
|
|
||||||
### Tuple expressions
|
### Tuple expressions
|
||||||
|
|
||||||
Tuples are written by enclosing two or more comma-separated
|
Tuples are written by enclosing one or more comma-separated
|
||||||
expressions in parentheses. They are used to create [tuple-typed](#tuple-types)
|
expressions in parentheses. They are used to create [tuple-typed](#tuple-types)
|
||||||
values.
|
values.
|
||||||
|
|
||||||
~~~~~~~~ {.tuple}
|
~~~~~~~~ {.tuple}
|
||||||
|
(0,);
|
||||||
(0f, 4.5f);
|
(0f, 4.5f);
|
||||||
("a", 4u, true);
|
("a", 4u, true);
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
@ -1796,6 +1838,7 @@ is bounds-checked at run-time. When the check fails, it will put the
|
|||||||
task in a _failing state_.
|
task in a _failing state_.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
|
# use std::task;
|
||||||
# do task::spawn_unlinked {
|
# do task::spawn_unlinked {
|
||||||
|
|
||||||
([1, 2, 3, 4])[0];
|
([1, 2, 3, 4])[0];
|
||||||
@ -1841,25 +1884,25 @@ Binary operators expressions are given in terms of
|
|||||||
#### Arithmetic operators
|
#### Arithmetic operators
|
||||||
|
|
||||||
Binary arithmetic expressions are syntactic sugar for calls to built-in traits,
|
Binary arithmetic expressions are syntactic sugar for calls to built-in traits,
|
||||||
defined in the `core::ops` module of the `core` library.
|
defined in the `std::ops` module of the `std` library.
|
||||||
This means that arithmetic operators can be overridden for user-defined types.
|
This means that arithmetic operators can be overridden for user-defined types.
|
||||||
The default meaning of the operators on standard types is given here.
|
The default meaning of the operators on standard types is given here.
|
||||||
|
|
||||||
`+`
|
`+`
|
||||||
: Addition and vector/string concatenation.
|
: Addition and vector/string concatenation.
|
||||||
Calls the `add` method on the `core::ops::Add` trait.
|
Calls the `add` method on the `std::ops::Add` trait.
|
||||||
`-`
|
`-`
|
||||||
: Subtraction.
|
: Subtraction.
|
||||||
Calls the `sub` method on the `core::ops::Sub` trait.
|
Calls the `sub` method on the `std::ops::Sub` trait.
|
||||||
`*`
|
`*`
|
||||||
: Multiplication.
|
: Multiplication.
|
||||||
Calls the `mul` method on the `core::ops::Mul` trait.
|
Calls the `mul` method on the `std::ops::Mul` trait.
|
||||||
`/`
|
`/`
|
||||||
: Division.
|
: Quotient.
|
||||||
Calls the `div` method on the `core::ops::Div` trait.
|
Calls the `div` method on the `std::ops::Div` trait.
|
||||||
`%`
|
`%`
|
||||||
: Modulo (a.k.a. "remainder").
|
: Remainder.
|
||||||
Calls the `modulo` method on the `core::ops::Modulo` trait.
|
Calls the `rem` method on the `std::ops::Rem` trait.
|
||||||
|
|
||||||
#### Bitwise operators
|
#### Bitwise operators
|
||||||
|
|
||||||
@ -1870,19 +1913,19 @@ The default meaning of the operators on standard types is given here.
|
|||||||
|
|
||||||
`&`
|
`&`
|
||||||
: And.
|
: And.
|
||||||
Calls the `bitand` method of the `core::ops::BitAnd` trait.
|
Calls the `bitand` method of the `std::ops::BitAnd` trait.
|
||||||
`|`
|
`|`
|
||||||
: Inclusive or.
|
: Inclusive or.
|
||||||
Calls the `bitor` method of the `core::ops::BitOr` trait.
|
Calls the `bitor` method of the `std::ops::BitOr` trait.
|
||||||
`^`
|
`^`
|
||||||
: Exclusive or.
|
: Exclusive or.
|
||||||
Calls the `bitxor` method of the `core::ops::BitXor` trait.
|
Calls the `bitxor` method of the `std::ops::BitXor` trait.
|
||||||
`<<`
|
`<<`
|
||||||
: Logical left shift.
|
: Logical left shift.
|
||||||
Calls the `shl` method of the `core::ops::Shl` trait.
|
Calls the `shl` method of the `std::ops::Shl` trait.
|
||||||
`>>`
|
`>>`
|
||||||
: Logical right shift.
|
: Logical right shift.
|
||||||
Calls the `shr` method of the `core::ops::Shr` trait.
|
Calls the `shr` method of the `std::ops::Shr` trait.
|
||||||
|
|
||||||
#### Lazy boolean operators
|
#### Lazy boolean operators
|
||||||
|
|
||||||
@ -1903,22 +1946,22 @@ The default meaning of the operators on standard types is given here.
|
|||||||
|
|
||||||
`==`
|
`==`
|
||||||
: Equal to.
|
: Equal to.
|
||||||
Calls the `eq` method on the `core::cmp::Eq` trait.
|
Calls the `eq` method on the `std::cmp::Eq` trait.
|
||||||
`!=`
|
`!=`
|
||||||
: Unequal to.
|
: Unequal to.
|
||||||
Calls the `ne` method on the `core::cmp::Eq` trait.
|
Calls the `ne` method on the `std::cmp::Eq` trait.
|
||||||
`<`
|
`<`
|
||||||
: Less than.
|
: Less than.
|
||||||
Calls the `lt` method on the `core::cmp::Ord` trait.
|
Calls the `lt` method on the `std::cmp::Ord` trait.
|
||||||
`>`
|
`>`
|
||||||
: Greater than.
|
: Greater than.
|
||||||
Calls the `gt` method on the `core::cmp::Ord` trait.
|
Calls the `gt` method on the `std::cmp::Ord` trait.
|
||||||
`<=`
|
`<=`
|
||||||
: Less than or equal.
|
: Less than or equal.
|
||||||
Calls the `le` method on the `core::cmp::Ord` trait.
|
Calls the `le` method on the `std::cmp::Ord` trait.
|
||||||
`>=`
|
`>=`
|
||||||
: Greater than or equal.
|
: Greater than or equal.
|
||||||
Calls the `ge` method on the `core::cmp::Ord` trait.
|
Calls the `ge` method on the `std::cmp::Ord` trait.
|
||||||
|
|
||||||
|
|
||||||
#### Type cast expressions
|
#### Type cast expressions
|
||||||
@ -1945,35 +1988,6 @@ fn avg(v: &[float]) -> float {
|
|||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
#### Swap expressions
|
|
||||||
|
|
||||||
A _swap expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) followed by a bi-directional arrow (`<->`) and another [lvalue](#lvalues-rvalues-and-temporaries).
|
|
||||||
|
|
||||||
Evaluating a swap expression causes, as a side effect, the values held in the left-hand-side and right-hand-side [lvalues](#lvalues-rvalues-and-temporaries) to be exchanged indivisibly.
|
|
||||||
|
|
||||||
Evaluating a swap expression neither changes reference counts,
|
|
||||||
nor deeply copies any owned structure pointed to by the moved [rvalue](#lvalues-rvalues-and-temporaries).
|
|
||||||
Instead, the swap expression represents an indivisible *exchange of ownership*,
|
|
||||||
between the right-hand-side and the left-hand-side of the expression.
|
|
||||||
No allocation or destruction is entailed.
|
|
||||||
|
|
||||||
An example of three different swap expressions:
|
|
||||||
|
|
||||||
~~~~~~~~
|
|
||||||
# let mut x = &mut [0];
|
|
||||||
# let mut a = &mut [0];
|
|
||||||
# let i = 0;
|
|
||||||
# struct S1 { z: int };
|
|
||||||
# struct S2 { c: int };
|
|
||||||
# let mut y = S1{z: 0};
|
|
||||||
# let mut b = S2{c: 0};
|
|
||||||
|
|
||||||
x <-> a;
|
|
||||||
x[i] <-> a[i];
|
|
||||||
y.z <-> b.c;
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
|
|
||||||
#### Assignment expressions
|
#### Assignment expressions
|
||||||
|
|
||||||
An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
|
An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
|
||||||
@ -2014,10 +2028,11 @@ as
|
|||||||
== !=
|
== !=
|
||||||
&&
|
&&
|
||||||
||
|
||
|
||||||
= <->
|
=
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Operators at the same precedence level are evaluated left-to-right.
|
Operators at the same precedence level are evaluated left-to-right. [Unary operators](#unary-operator-expressions)
|
||||||
|
have the same precedence level and it is stronger than any of the binary operators'.
|
||||||
|
|
||||||
### Grouped expressions
|
### Grouped expressions
|
||||||
|
|
||||||
@ -2106,11 +2121,11 @@ then the expression completes.
|
|||||||
Some examples of call expressions:
|
Some examples of call expressions:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::from_str::FromStr::from_str;
|
# use std::from_str::FromStr;
|
||||||
# fn add(x: int, y: int) -> int { 0 }
|
# fn add(x: int, y: int) -> int { 0 }
|
||||||
|
|
||||||
let x: int = add(1, 2);
|
let x: int = add(1, 2);
|
||||||
let pi = from_str::<f32>("3.14");
|
let pi = FromStr::from_str::<f32>("3.14");
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
### Lambda expressions
|
### Lambda expressions
|
||||||
@ -2153,7 +2168,7 @@ fn ten_times(f: &fn(int)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ten_times(|j| io::println(fmt!("hello, %d", j)));
|
ten_times(|j| println(fmt!("hello, %d", j)));
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
@ -2174,7 +2189,7 @@ An example:
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
while i < 10 {
|
while i < 10 {
|
||||||
io::println("hello\n");
|
println("hello\n");
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
@ -2186,7 +2201,7 @@ A loop expression denotes an infinite loop;
|
|||||||
see [Continue expressions](#continue-expressions) for continue expressions.
|
see [Continue expressions](#continue-expressions) for continue expressions.
|
||||||
|
|
||||||
~~~~~~~~{.ebnf .gram}
|
~~~~~~~~{.ebnf .gram}
|
||||||
loop_expr : "loop" [ ident ':' ] '{' block '}';
|
loop_expr : [ lifetime ':' ] "loop" '{' block '}';
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
A `loop` expression may optionally have a _label_.
|
A `loop` expression may optionally have a _label_.
|
||||||
@ -2197,7 +2212,7 @@ See [Break expressions](#break-expressions).
|
|||||||
### Break expressions
|
### Break expressions
|
||||||
|
|
||||||
~~~~~~~~{.ebnf .gram}
|
~~~~~~~~{.ebnf .gram}
|
||||||
break_expr : "break" [ ident ];
|
break_expr : "break" [ lifetime ];
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
A `break` expression has an optional `label`.
|
A `break` expression has an optional `label`.
|
||||||
@ -2210,7 +2225,7 @@ but must enclose it.
|
|||||||
### Continue expressions
|
### Continue expressions
|
||||||
|
|
||||||
~~~~~~~~{.ebnf .gram}
|
~~~~~~~~{.ebnf .gram}
|
||||||
continue_expr : "loop" [ ident ];
|
continue_expr : "loop" [ lifetime ];
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
A continue expression, written `loop`, also has an optional `label`.
|
A continue expression, written `loop`, also has an optional `label`.
|
||||||
@ -2236,6 +2251,14 @@ do_expr : "do" expr [ '|' ident_list '|' ] ? '{' block '}' ;
|
|||||||
A _do expression_ provides a more-familiar block-syntax for a [lambda expression](#lambda-expressions),
|
A _do expression_ provides a more-familiar block-syntax for a [lambda expression](#lambda-expressions),
|
||||||
including a special translation of [return expressions](#return-expressions) inside the supplied block.
|
including a special translation of [return expressions](#return-expressions) inside the supplied block.
|
||||||
|
|
||||||
|
Any occurrence of a [return expression](#return-expressions)
|
||||||
|
inside this `block` expression is rewritten
|
||||||
|
as a reference to an (anonymous) flag set in the caller's environment,
|
||||||
|
which is checked on return from the `expr` and, if set,
|
||||||
|
causes a corresponding return from the caller.
|
||||||
|
In this way, the meaning of `return` statements in language built-in control blocks is preserved,
|
||||||
|
if they are rewritten using lambda functions and `do` expressions as abstractions.
|
||||||
|
|
||||||
The optional `ident_list` and `block` provided in a `do` expression are parsed as though they constitute a lambda expression;
|
The optional `ident_list` and `block` provided in a `do` expression are parsed as though they constitute a lambda expression;
|
||||||
if the `ident_list` is missing, an empty `ident_list` is implied.
|
if the `ident_list` is missing, an empty `ident_list` is implied.
|
||||||
|
|
||||||
@ -2282,19 +2305,15 @@ A _for expression_ is similar to a [`do` expression](#do-expressions),
|
|||||||
in that it provides a special block-form of lambda expression,
|
in that it provides a special block-form of lambda expression,
|
||||||
suited to passing the `block` function to a higher-order function implementing a loop.
|
suited to passing the `block` function to a higher-order function implementing a loop.
|
||||||
|
|
||||||
Like a `do` expression, a `return` expression inside a `for` expresison is rewritten,
|
In contrast to a `do` expression, a `for` expression is designed to work
|
||||||
to access a local flag that causes an early return in the caller.
|
with methods such as `each` and `times`, that require the body block to
|
||||||
|
return a boolean. The `for` expression accommodates this by implicitly
|
||||||
|
returning `true` at the end of each block, unless a `break` expression
|
||||||
|
is evaluated.
|
||||||
|
|
||||||
Additionally, any occurrence of a [return expression](#return-expressions)
|
In addition, [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
|
||||||
inside the `block` of a `for` expression is rewritten
|
are rewritten inside `for` expressions in the same way that `return` expressions are,
|
||||||
as a reference to an (anonymous) flag set in the caller's environment,
|
with a combination of local flag variables,
|
||||||
which is checked on return from the `expr` and, if set,
|
|
||||||
causes a corresponding return from the caller.
|
|
||||||
In this way, the meaning of `return` statements in language built-in control blocks is preserved,
|
|
||||||
if they are rewritten using lambda functions and `do` expressions as abstractions.
|
|
||||||
|
|
||||||
Like `return` expressions, any [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
|
|
||||||
are rewritten inside `for` expressions, with a combination of local flag variables,
|
|
||||||
and early boolean-valued returns from the `block` function,
|
and early boolean-valued returns from the `block` function,
|
||||||
such that the meaning of `break` and `loop` is preserved in a primitive loop
|
such that the meaning of `break` and `loop` is preserved in a primitive loop
|
||||||
when rewritten as a `for` loop controlled by a higher order function.
|
when rewritten as a `for` loop controlled by a higher order function.
|
||||||
@ -2304,11 +2323,13 @@ An example of a for loop over the contents of a vector:
|
|||||||
~~~~
|
~~~~
|
||||||
# type foo = int;
|
# type foo = int;
|
||||||
# fn bar(f: foo) { }
|
# fn bar(f: foo) { }
|
||||||
# let a = 0, b = 0, c = 0;
|
# let a = 0;
|
||||||
|
# let b = 0;
|
||||||
|
# let c = 0;
|
||||||
|
|
||||||
let v: &[foo] = &[a, b, c];
|
let v: &[foo] = &[a, b, c];
|
||||||
|
|
||||||
for v.each |e| {
|
for v.iter().advance |e| {
|
||||||
bar(*e);
|
bar(*e);
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
@ -2316,6 +2337,7 @@ for v.each |e| {
|
|||||||
An example of a for loop over a series of integers:
|
An example of a for loop over a series of integers:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
|
# use std::uint;
|
||||||
# fn bar(b:uint) { }
|
# fn bar(b:uint) { }
|
||||||
for uint::range(0, 256) |i| {
|
for uint::range(0, 256) |i| {
|
||||||
bar(i);
|
bar(i);
|
||||||
@ -2372,9 +2394,9 @@ enum List<X> { Nil, Cons(X, @List<X>) }
|
|||||||
let x: List<int> = Cons(10, @Cons(11, @Nil));
|
let x: List<int> = Cons(10, @Cons(11, @Nil));
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
Cons(_, @Nil) => fail!(~"singleton list"),
|
Cons(_, @Nil) => fail!("singleton list"),
|
||||||
Cons(*) => return,
|
Cons(*) => return,
|
||||||
Nil => fail!(~"empty list")
|
Nil => fail!("empty list")
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
@ -2416,10 +2438,11 @@ match x {
|
|||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Patterns that bind variables default to binding to a copy of the matched value. This can be made
|
Patterns that bind variables default to binding to a copy or move of the matched value
|
||||||
explicit using the ```copy``` keyword, changed to bind to a borrowed pointer by using the ```ref```
|
(depending on the matched value's type).
|
||||||
keyword, or to a mutable borrowed pointer using ```ref mut```, or the value can be moved into
|
This can be made explicit using the ```copy``` keyword,
|
||||||
the new binding using ```move```.
|
changed to bind to a borrowed pointer by using the ```ref``` keyword,
|
||||||
|
or to a mutable borrowed pointer using ```ref mut```.
|
||||||
|
|
||||||
A pattern that's just an identifier,
|
A pattern that's just an identifier,
|
||||||
like `Nil` in the previous answer,
|
like `Nil` in the previous answer,
|
||||||
@ -2578,7 +2601,7 @@ to the record type-constructor. The differences are as follows:
|
|||||||
|
|
||||||
Tuple types and values are denoted by listing the types or values of their
|
Tuple types and values are denoted by listing the types or values of their
|
||||||
elements, respectively, in a parenthesized, comma-separated
|
elements, respectively, in a parenthesized, comma-separated
|
||||||
list. Single-element tuples are not legal; all tuples have two or more values.
|
list.
|
||||||
|
|
||||||
The members of a tuple are laid out in memory contiguously, like a record, in
|
The members of a tuple are laid out in memory contiguously, like a record, in
|
||||||
order specified by the tuple type.
|
order specified by the tuple type.
|
||||||
@ -2597,7 +2620,7 @@ assert!(b != "world");
|
|||||||
|
|
||||||
The vector type constructor represents a homogeneous array of values of a given type.
|
The vector type constructor represents a homogeneous array of values of a given type.
|
||||||
A vector has a fixed size.
|
A vector has a fixed size.
|
||||||
(Operations like `vec::push` operate solely on owned vectors.)
|
(Operations like `vec.push` operate solely on owned vectors.)
|
||||||
A vector type can be annotated with a _definite_ size,
|
A vector type can be annotated with a _definite_ size,
|
||||||
written with a trailing asterisk and integer literal, such as `[int * 10]`.
|
written with a trailing asterisk and integer literal, such as `[int * 10]`.
|
||||||
Such a definite-sized vector type is a first-class type, since its size is known statically.
|
Such a definite-sized vector type is a first-class type, since its size is known statically.
|
||||||
@ -2778,6 +2801,7 @@ the vtable pointer for the `T` implementation of `R`, and the pointer value of `
|
|||||||
An example of an object type:
|
An example of an object type:
|
||||||
|
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
# use std::int;
|
||||||
trait Printable {
|
trait Printable {
|
||||||
fn to_str(&self) -> ~str;
|
fn to_str(&self) -> ~str;
|
||||||
}
|
}
|
||||||
@ -2787,7 +2811,7 @@ impl Printable for int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print(a: @Printable) {
|
fn print(a: @Printable) {
|
||||||
io::println(a.to_str());
|
println(a.to_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -2805,7 +2829,7 @@ Within the body of an item that has type parameter declarations, the names of it
|
|||||||
~~~~~~~
|
~~~~~~~
|
||||||
fn map<A: Copy, B: Copy>(f: &fn(A) -> B, xs: &[A]) -> ~[B] {
|
fn map<A: Copy, B: Copy>(f: &fn(A) -> B, xs: &[A]) -> ~[B] {
|
||||||
if xs.len() == 0 { return ~[]; }
|
if xs.len() == 0 { return ~[]; }
|
||||||
let first: B = f(xs[0]);
|
let first: B = f(copy xs[0]);
|
||||||
let rest: ~[B] = map(f, xs.slice(1, xs.len()));
|
let rest: ~[B] = map(f, xs.slice(1, xs.len()));
|
||||||
return ~[first] + rest;
|
return ~[first] + rest;
|
||||||
}
|
}
|
||||||
@ -2838,13 +2862,13 @@ call to the method `make_string`.
|
|||||||
Types in Rust are categorized into kinds, based on various properties of the components of the type.
|
Types in Rust are categorized into kinds, based on various properties of the components of the type.
|
||||||
The kinds are:
|
The kinds are:
|
||||||
|
|
||||||
`Const`
|
`Freeze`
|
||||||
: Types of this kind are deeply immutable;
|
: Types of this kind are deeply immutable;
|
||||||
they contain no mutable memory locations directly or indirectly via pointers.
|
they contain no mutable memory locations directly or indirectly via pointers.
|
||||||
`Owned`
|
`Send`
|
||||||
: Types of this kind can be safely sent between tasks.
|
: Types of this kind can be safely sent between tasks.
|
||||||
This kind includes scalars, owning pointers, owned closures, and
|
This kind includes scalars, owning pointers, owned closures, and
|
||||||
structural types containing only other owned types. All `Owned` types are `Static`.
|
structural types containing only other owned types. All `Send` types are `Static`.
|
||||||
`Static`
|
`Static`
|
||||||
: Types of this kind do not contain any borrowed pointers;
|
: Types of this kind do not contain any borrowed pointers;
|
||||||
this can be a useful guarantee for code that breaks borrowing assumptions using [`unsafe` operations](#unsafe-functions).
|
this can be a useful guarantee for code that breaks borrowing assumptions using [`unsafe` operations](#unsafe-functions).
|
||||||
@ -2858,7 +2882,7 @@ The kinds are:
|
|||||||
trait provides a single method `finalize` that takes no parameters, and is run
|
trait provides a single method `finalize` that takes no parameters, and is run
|
||||||
when values of the type are dropped. Such a method is called a "destructor",
|
when values of the type are dropped. Such a method is called a "destructor",
|
||||||
and are always executed in "top-down" order: a value is completely destroyed
|
and are always executed in "top-down" order: a value is completely destroyed
|
||||||
before any of the values it owns run their destructors. Only `Owned` types
|
before any of the values it owns run their destructors. Only `Send` types
|
||||||
that do not implement `Copy` can implement `Drop`.
|
that do not implement `Copy` can implement `Drop`.
|
||||||
|
|
||||||
> **Note:** The `finalize` method may be renamed in future versions of Rust.
|
> **Note:** The `finalize` method may be renamed in future versions of Rust.
|
||||||
@ -2944,10 +2968,10 @@ frame they are allocated within.
|
|||||||
A task owns all memory it can *safely* reach through local variables,
|
A task owns all memory it can *safely* reach through local variables,
|
||||||
as well as managed, owning and borrowed pointers.
|
as well as managed, owning and borrowed pointers.
|
||||||
|
|
||||||
When a task sends a value that has the `Owned` trait to another task,
|
When a task sends a value that has the `Send` trait to another task,
|
||||||
it loses ownership of the value sent and can no longer refer to it.
|
it loses ownership of the value sent and can no longer refer to it.
|
||||||
This is statically guaranteed by the combined use of "move semantics",
|
This is statically guaranteed by the combined use of "move semantics",
|
||||||
and the compiler-checked _meaning_ of the `Owned` trait:
|
and the compiler-checked _meaning_ of the `Send` trait:
|
||||||
it is only instantiated for (transitively) sendable kinds of data constructor and pointers,
|
it is only instantiated for (transitively) sendable kinds of data constructor and pointers,
|
||||||
never including managed or borrowed pointers.
|
never including managed or borrowed pointers.
|
||||||
|
|
||||||
@ -2976,7 +3000,7 @@ allocated within the stack's memory. The value is a part of the stack frame.
|
|||||||
|
|
||||||
Local variables are immutable unless declared with `let mut`. The
|
Local variables are immutable unless declared with `let mut`. The
|
||||||
`mut` keyword applies to all local variables declared within that
|
`mut` keyword applies to all local variables declared within that
|
||||||
declaration (so `let mut x, y` declares two mutable variables, `x` and
|
declaration (so `let mut (x, y) = ...` declares two mutable variables, `x` and
|
||||||
`y`).
|
`y`).
|
||||||
|
|
||||||
Function parameters are immutable unless declared with `mut`. The
|
Function parameters are immutable unless declared with `mut`. The
|
||||||
@ -3092,7 +3116,7 @@ These include:
|
|||||||
- read-only and read-write shared variables with various safe mutual exclusion patterns
|
- read-only and read-write shared variables with various safe mutual exclusion patterns
|
||||||
- simple locks and semaphores
|
- simple locks and semaphores
|
||||||
|
|
||||||
When such facilities carry values, the values are restricted to the [`Owned` type-kind](#type-kinds).
|
When such facilities carry values, the values are restricted to the [`Send` type-kind](#type-kinds).
|
||||||
Restricting communication interfaces to this kind ensures that no borrowed or managed pointers move between tasks.
|
Restricting communication interfaces to this kind ensures that no borrowed or managed pointers move between tasks.
|
||||||
Thus access to an entire data structure can be mediated through its owning "root" value;
|
Thus access to an entire data structure can be mediated through its owning "root" value;
|
||||||
no further locking or copying is required to avoid data races within the substructure of such a value.
|
no further locking or copying is required to avoid data races within the substructure of such a value.
|
||||||
@ -3149,7 +3173,7 @@ execute, after which it is *descheduled* at a loop-edge or similar
|
|||||||
preemption point, and another task within is scheduled, pseudo-randomly.
|
preemption point, and another task within is scheduled, pseudo-randomly.
|
||||||
|
|
||||||
An executing task can yield control at any time, by making a library call to
|
An executing task can yield control at any time, by making a library call to
|
||||||
`core::task::yield`, which deschedules it immediately. Entering any other
|
`std::task::yield`, which deschedules it immediately. Entering any other
|
||||||
non-executing state (blocked, dead) similarly deschedules the task.
|
non-executing state (blocked, dead) similarly deschedules the task.
|
||||||
|
|
||||||
|
|
||||||
@ -3162,7 +3186,7 @@ run-time. It is smaller and simpler than many modern language runtimes. It is
|
|||||||
tightly integrated into the language's execution model of memory, tasks,
|
tightly integrated into the language's execution model of memory, tasks,
|
||||||
communication and logging.
|
communication and logging.
|
||||||
|
|
||||||
> **Note:** The runtime library will merge with the `core` library in future versions of Rust.
|
> **Note:** The runtime library will merge with the `std` library in future versions of Rust.
|
||||||
|
|
||||||
### Memory allocation
|
### Memory allocation
|
||||||
|
|
||||||
@ -3251,6 +3275,28 @@ of runtime logging modules follows.
|
|||||||
* `::rt::backtrace` Log a backtrace on task failure
|
* `::rt::backtrace` Log a backtrace on task failure
|
||||||
* `::rt::callback` Unused
|
* `::rt::callback` Unused
|
||||||
|
|
||||||
|
#### Logging Expressions
|
||||||
|
|
||||||
|
Rust provides several macros to log information. Here's a simple Rust program
|
||||||
|
that demonstrates all four of them:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
error!("This is an error log")
|
||||||
|
warn!("This is a warn log")
|
||||||
|
info!("this is an info log")
|
||||||
|
debug!("This is a debug log")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ RUST_LOG=rust=3 ./rust
|
||||||
|
rust: ~"\"This is an error log\""
|
||||||
|
rust: ~"\"This is a warn log\""
|
||||||
|
rust: ~"\"this is an info log\""
|
||||||
|
```
|
||||||
|
|
||||||
# Appendix: Rationales and design tradeoffs
|
# Appendix: Rationales and design tradeoffs
|
||||||
|
|
||||||
@ -3328,4 +3374,3 @@ Additional specific influences can be seen from the following languages:
|
|||||||
* The typeclass system of Haskell.
|
* The typeclass system of Haskell.
|
||||||
* The lexical identifier rule of Python.
|
* The lexical identifier rule of Python.
|
||||||
* The block syntax of Ruby.
|
* The block syntax of Ruby.
|
||||||
|
|
||||||
|
137
doc/rustpkg.md
Normal file
137
doc/rustpkg.md
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
% Rustpkg Reference Manual
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
This document is the reference manual for the Rustpkg packaging and build tool for the Rust programming language.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
Rustpkg is a work in progress, as is this reference manual.
|
||||||
|
If the actual behavior of rustpkg differs from the behavior described in this reference,
|
||||||
|
that reflects either an incompleteness or a bug in rustpkg.
|
||||||
|
|
||||||
|
# Package searching
|
||||||
|
|
||||||
|
rustpkg searches for packages using the `RUST_PATH` environment variable,
|
||||||
|
which is a colon-separated list (semicolon-separated on Windows) of directories.
|
||||||
|
|
||||||
|
Each directory in this list is a *workspace* for rustpkg.
|
||||||
|
|
||||||
|
`RUST_PATH` implicitly contains an entry for `./.rust` (as well as
|
||||||
|
`../.rust`, `../../.rust`,
|
||||||
|
and so on for every parent of `.` up to the filesystem root).
|
||||||
|
That means that if `RUST_PATH` is not set,
|
||||||
|
then rustpkg will still search for workspaces in `./.rust` and so on.
|
||||||
|
`RUST_PATH` also implicitly contains an entry for the system path:
|
||||||
|
`/usr/local` or the equivalent on Windows.
|
||||||
|
This entry comes after the implicit entries for `./.rust` and so on.
|
||||||
|
Finally, the last implicit entry in `RUST_PATH` is `~/.rust`
|
||||||
|
or the equivalent on Windows.
|
||||||
|
|
||||||
|
Each workspace may contain one or more packages.
|
||||||
|
|
||||||
|
When building code that contains one or more directives of the form `extern mod P`,
|
||||||
|
rustpkg automatically searches for packages named `P` in the `RUST_PATH` (as described above).
|
||||||
|
It builds those dependencies if necessary.
|
||||||
|
Thus, when using rustpkg,
|
||||||
|
there is no need for `-L` flags to tell the linker where to find libraries for external crates.
|
||||||
|
|
||||||
|
# Package structure
|
||||||
|
|
||||||
|
A valid workspace must contain each of the following subdirectories:
|
||||||
|
|
||||||
|
* 'src/': contains one subdirectory per package. Each subdirectory contains source files for a given package.
|
||||||
|
|
||||||
|
For example, if `foo` is a workspace containing the package `bar`,
|
||||||
|
then `foo/src/bar/main.rs` could be the `main` entry point for
|
||||||
|
building a `bar` executable.
|
||||||
|
* 'lib/': `rustpkg install` installs libraries into a target-specific subdirectory of this directory.
|
||||||
|
|
||||||
|
For example, on a 64-bit machine running Mac OS X,
|
||||||
|
if `foo` is a workspace containing the package `bar`,
|
||||||
|
rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
|
||||||
|
The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
|
||||||
|
where [hash] is a hash of the package ID.
|
||||||
|
* 'bin/': `rustpkg install` installs executable binaries into a target-specific subdirectory of this directory.
|
||||||
|
|
||||||
|
For example, on a 64-bit machine running Mac OS X,
|
||||||
|
if `foo` is a workspace, containing the package `bar`,
|
||||||
|
rustpkg will install executables for `bar` to
|
||||||
|
`foo/bin/x86_64-apple-darwin/`.
|
||||||
|
The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`.
|
||||||
|
* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
|
||||||
|
|
||||||
|
For example, on a 64-bit machine running Mac OS X,
|
||||||
|
if `foo` is a workspace containing the package `bar` and `foo/src/bar/main.rs` exists,
|
||||||
|
then `rustpkg build` will create `foo/build/x86_64-apple-darwin/bar/main.o`.
|
||||||
|
|
||||||
|
# Package identifiers
|
||||||
|
|
||||||
|
A package identifier identifies a package uniquely.
|
||||||
|
A package can be stored in a workspace on the local file system,
|
||||||
|
or on a remote Web server, in which case the package ID resembles a URL.
|
||||||
|
For example, `github.com/mozilla/rust` is a package ID
|
||||||
|
that would refer to the git repository browsable at `http://github.com/mozilla/rust`.
|
||||||
|
A package ID can also specify a version, like:
|
||||||
|
`github.com/mozilla/rust#0.3`.
|
||||||
|
In this case, `rustpkg` will check that the repository `github.com/mozilla/rust` has a tag named `0.3`,
|
||||||
|
and report an error otherwise.
|
||||||
|
|
||||||
|
## Source files
|
||||||
|
|
||||||
|
rustpkg searches for four different fixed filenames in order to determine the crates to build:
|
||||||
|
|
||||||
|
* `main.rs`: Assumed to be a main entry point for building an executable.
|
||||||
|
* `lib.rs`: Assumed to be a library crate.
|
||||||
|
* `test.rs`: Assumed to contain tests declared with the `#[test]` attribute.
|
||||||
|
* `bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` attribute.
|
||||||
|
|
||||||
|
## Versions
|
||||||
|
|
||||||
|
`rustpkg` packages do not need to declare their versions with an attribute inside one of the source files,
|
||||||
|
because `rustpkg` infers it from the version control system.
|
||||||
|
When building a package that is in a `git` repository,
|
||||||
|
`rustpkg` assumes that the most recent tag specifies the current version.
|
||||||
|
When building a package that is not under version control,
|
||||||
|
or that has no tags, `rustpkg` assumes the intended version is 0.1.
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
rustpkg infers dependencies from `extern mod` directives.
|
||||||
|
Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library.
|
||||||
|
(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.)
|
||||||
|
|
||||||
|
# Custom build scripts
|
||||||
|
|
||||||
|
A file called `pkg.rs` at the root level in a workspace is called a *package script*.
|
||||||
|
If a package script exists, rustpkg executes it to build the package
|
||||||
|
rather than inferring crates as described previously.
|
||||||
|
|
||||||
|
Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build.
|
||||||
|
`rustpkg::api` contains functions to build, install, or clean libraries and executables
|
||||||
|
in the way rustpkg normally would without custom build logic.
|
||||||
|
|
||||||
|
# Command reference
|
||||||
|
|
||||||
|
## build
|
||||||
|
|
||||||
|
`rustpkg build foo` searches for a package with ID `foo`
|
||||||
|
and builds it in any workspace(s) where it finds one.
|
||||||
|
Supposing such packages are found in workspaces X, Y, and Z,
|
||||||
|
the command leaves behind files in `X`'s, `Y`'s, and `Z`'s `build` directories,
|
||||||
|
but not in their `lib` or `bin` directories.
|
||||||
|
|
||||||
|
## clean
|
||||||
|
|
||||||
|
`rustpkg clean foo` deletes the contents of `foo`'s `build` directory.
|
||||||
|
|
||||||
|
## install
|
||||||
|
|
||||||
|
`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`,
|
||||||
|
and then installs them either into `foo`'s `lib` and `bin` directories,
|
||||||
|
or into the `lib` and `bin` subdirectories of the first entry in `RUST_PATH`.
|
||||||
|
|
||||||
|
## test
|
||||||
|
|
||||||
|
`rustpkg test foo` builds `foo`'s `test.rs` file if necessary,
|
||||||
|
then runs the resulting test executable.
|
@ -42,14 +42,14 @@ point, but allocated in a different place:
|
|||||||
~~~
|
~~~
|
||||||
# struct Point {x: float, y: float}
|
# struct Point {x: float, y: float}
|
||||||
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
||||||
let shared_box : @Point = @Point {x: 5.0, y: 1.0};
|
let managed_box : @Point = @Point {x: 5.0, y: 1.0};
|
||||||
let unique_box : ~Point = ~Point {x: 7.0, y: 9.0};
|
let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Suppose we wanted to write a procedure that computed the distance between any
|
Suppose we wanted to write a procedure that computed the distance between any
|
||||||
two points, no matter where they were stored. For example, we might like to
|
two points, no matter where they were stored. For example, we might like to
|
||||||
compute the distance between `on_the_stack` and `shared_box`, or between
|
compute the distance between `on_the_stack` and `managed_box`, or between
|
||||||
`shared_box` and `unique_box`. One option is to define a function that takes
|
`managed_box` and `owned_box`. One option is to define a function that takes
|
||||||
two arguments of type `Point`—that is, it takes the points by value. But if we
|
two arguments of type `Point`—that is, it takes the points by value. But if we
|
||||||
define it this way, calling the function will cause the points to be
|
define it this way, calling the function will cause the points to be
|
||||||
copied. For points, this is probably not so bad, but often copies are
|
copied. For points, this is probably not so bad, but often copies are
|
||||||
@ -73,11 +73,11 @@ Now we can call `compute_distance()` in various ways:
|
|||||||
~~~
|
~~~
|
||||||
# struct Point {x: float, y: float}
|
# struct Point {x: float, y: float}
|
||||||
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
||||||
# let shared_box : @Point = @Point{x: 5.0, y: 1.0};
|
# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
|
||||||
# let unique_box : ~Point = ~Point{x: 7.0, y: 9.0};
|
# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};
|
||||||
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
|
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
|
||||||
compute_distance(&on_the_stack, shared_box);
|
compute_distance(&on_the_stack, managed_box);
|
||||||
compute_distance(shared_box, unique_box);
|
compute_distance(managed_box, owned_box);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Here, the `&` operator takes the address of the variable
|
Here, the `&` operator takes the address of the variable
|
||||||
@ -87,11 +87,11 @@ value. We also call this _borrowing_ the local variable
|
|||||||
`on_the_stack`, because we have created an alias: that is, another
|
`on_the_stack`, because we have created an alias: that is, another
|
||||||
name for the same data.
|
name for the same data.
|
||||||
|
|
||||||
In contrast, we can pass the boxes `shared_box` and `unique_box` to
|
In contrast, we can pass the boxes `managed_box` and `owned_box` to
|
||||||
`compute_distance` directly. The compiler automatically converts a box like
|
`compute_distance` directly. The compiler automatically converts a box like
|
||||||
`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another form
|
`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another form
|
||||||
of borrowing: in this case, the caller lends the contents of the shared or
|
of borrowing: in this case, the caller lends the contents of the managed or
|
||||||
unique box to the callee.
|
owned box to the callee.
|
||||||
|
|
||||||
Whenever a caller lends data to a callee, there are some limitations on what
|
Whenever a caller lends data to a callee, there are some limitations on what
|
||||||
the caller can do with the original. For example, if the contents of a
|
the caller can do with the original. For example, if the contents of a
|
||||||
@ -155,7 +155,7 @@ let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f},
|
|||||||
size: Size {w: 3f, h: 4f}};
|
size: Size {w: 3f, h: 4f}};
|
||||||
let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},
|
let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},
|
||||||
size: Size {w: 3f, h: 4f}};
|
size: Size {w: 3f, h: 4f}};
|
||||||
let rect_unique = ~Rectangle {origin: Point {x: 5f, y: 6f},
|
let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f},
|
||||||
size: Size {w: 3f, h: 4f}};
|
size: Size {w: 3f, h: 4f}};
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ operator. For example, I could write:
|
|||||||
# struct Rectangle {origin: Point, size: Size}
|
# struct Rectangle {origin: Point, size: Size}
|
||||||
# let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f}, size: Size {w: 3f, h: 4f}};
|
# let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f}, size: Size {w: 3f, h: 4f}};
|
||||||
# let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f}, size: Size {w: 3f, h: 4f}};
|
# let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f}, size: Size {w: 3f, h: 4f}};
|
||||||
# let rect_unique = ~Rectangle {origin: Point {x: 5f, y: 6f}, size: Size {w: 3f, h: 4f}};
|
# let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f}, size: Size {w: 3f, h: 4f}};
|
||||||
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
|
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
|
||||||
compute_distance(&rect_stack.origin, &rect_managed.origin);
|
compute_distance(&rect_stack.origin, &rect_managed.origin);
|
||||||
~~~
|
~~~
|
||||||
@ -179,7 +179,7 @@ as well as from the managed box, and then compute the distance between them.
|
|||||||
# Borrowing managed boxes and rooting
|
# Borrowing managed boxes and rooting
|
||||||
|
|
||||||
We’ve seen a few examples so far of borrowing heap boxes, both managed
|
We’ve seen a few examples so far of borrowing heap boxes, both managed
|
||||||
and unique. Up till this point, we’ve glossed over issues of
|
and owned. Up till this point, we’ve glossed over issues of
|
||||||
safety. As stated in the introduction, at runtime a borrowed pointer
|
safety. As stated in the introduction, at runtime a borrowed pointer
|
||||||
is simply a pointer, nothing more. Therefore, avoiding C's problems
|
is simply a pointer, nothing more. Therefore, avoiding C's problems
|
||||||
with dangling pointers requires a compile-time safety check.
|
with dangling pointers requires a compile-time safety check.
|
||||||
@ -234,7 +234,7 @@ would therefore be subject to garbage collection. A heap box that is
|
|||||||
unrooted is one such that no pointer values in the heap point to
|
unrooted is one such that no pointer values in the heap point to
|
||||||
it. It would violate memory safety for the box that was originally
|
it. It would violate memory safety for the box that was originally
|
||||||
assigned to `x` to be garbage-collected, since a non-heap
|
assigned to `x` to be garbage-collected, since a non-heap
|
||||||
pointer---`y`---still points into it.
|
pointer *`y`* still points into it.
|
||||||
|
|
||||||
> ***Note:*** Our current implementation implements the garbage collector
|
> ***Note:*** Our current implementation implements the garbage collector
|
||||||
> using reference counting and cycle detection.
|
> using reference counting and cycle detection.
|
||||||
@ -258,18 +258,18 @@ fn example2() {
|
|||||||
Now if `x` is reassigned, the pointer `y` will still remain valid. This
|
Now if `x` is reassigned, the pointer `y` will still remain valid. This
|
||||||
process is called *rooting*.
|
process is called *rooting*.
|
||||||
|
|
||||||
# Borrowing unique boxes
|
# Borrowing owned boxes
|
||||||
|
|
||||||
The previous example demonstrated *rooting*, the process by which the
|
The previous example demonstrated *rooting*, the process by which the
|
||||||
compiler ensures that managed boxes remain live for the duration of a
|
compiler ensures that managed boxes remain live for the duration of a
|
||||||
borrow. Unfortunately, rooting does not work for borrows of unique
|
borrow. Unfortunately, rooting does not work for borrows of owned
|
||||||
boxes, because it is not possible to have two references to a unique
|
boxes, because it is not possible to have two references to a owned
|
||||||
box.
|
box.
|
||||||
|
|
||||||
For unique boxes, therefore, the compiler will only allow a borrow *if
|
For owned boxes, therefore, the compiler will only allow a borrow *if
|
||||||
the compiler can guarantee that the unique box will not be reassigned
|
the compiler can guarantee that the owned box will not be reassigned
|
||||||
or moved for the lifetime of the pointer*. This does not necessarily
|
or moved for the lifetime of the pointer*. This does not necessarily
|
||||||
mean that the unique box is stored in immutable memory. For example,
|
mean that the owned box is stored in immutable memory. For example,
|
||||||
the following function is legal:
|
the following function is legal:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
@ -294,7 +294,7 @@ and `x` is declared as mutable. However, the compiler can prove that
|
|||||||
and in fact is mutated later in the function.
|
and in fact is mutated later in the function.
|
||||||
|
|
||||||
It may not be clear why we are so concerned about mutating a borrowed
|
It may not be clear why we are so concerned about mutating a borrowed
|
||||||
variable. The reason is that the runtime system frees any unique box
|
variable. The reason is that the runtime system frees any owned box
|
||||||
_as soon as its owning reference changes or goes out of
|
_as soon as its owning reference changes or goes out of
|
||||||
scope_. Therefore, a program like this is illegal (and would be
|
scope_. Therefore, a program like this is illegal (and would be
|
||||||
rejected by the compiler):
|
rejected by the compiler):
|
||||||
@ -342,7 +342,7 @@ which has been freed.
|
|||||||
|
|
||||||
In fact, the compiler can apply the same kind of reasoning to any
|
In fact, the compiler can apply the same kind of reasoning to any
|
||||||
memory that is _(uniquely) owned by the stack frame_. So we could
|
memory that is _(uniquely) owned by the stack frame_. So we could
|
||||||
modify the previous example to introduce additional unique pointers
|
modify the previous example to introduce additional owned pointers
|
||||||
and structs, and the compiler will still be able to detect possible
|
and structs, and the compiler will still be able to detect possible
|
||||||
mutations:
|
mutations:
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ invalidate the pointer `y`.
|
|||||||
# Borrowing and enums
|
# Borrowing and enums
|
||||||
|
|
||||||
The previous example showed that the type system forbids any borrowing
|
The previous example showed that the type system forbids any borrowing
|
||||||
of unique boxes found in aliasable, mutable memory. This restriction
|
of owned boxes found in aliasable, mutable memory. This restriction
|
||||||
prevents pointers from pointing into freed memory. There is one other
|
prevents pointers from pointing into freed memory. There is one other
|
||||||
case where the compiler must be very careful to ensure that pointers
|
case where the compiler must be very careful to ensure that pointers
|
||||||
remain valid: pointers into the interior of an `enum`.
|
remain valid: pointers into the interior of an `enum`.
|
||||||
@ -462,20 +462,20 @@ of a `float` as if it were a struct with two fields would be a memory
|
|||||||
safety violation.
|
safety violation.
|
||||||
|
|
||||||
So, in fact, for every `ref` binding, the compiler will impose the
|
So, in fact, for every `ref` binding, the compiler will impose the
|
||||||
same rules as the ones we saw for borrowing the interior of a unique
|
same rules as the ones we saw for borrowing the interior of a owned
|
||||||
box: it must be able to guarantee that the `enum` will not be
|
box: it must be able to guarantee that the `enum` will not be
|
||||||
overwritten for the duration of the borrow. In fact, the compiler
|
overwritten for the duration of the borrow. In fact, the compiler
|
||||||
would accept the example we gave earlier. The example is safe because
|
would accept the example we gave earlier. The example is safe because
|
||||||
the shape pointer has type `&Shape`, which means "borrowed pointer to
|
the shape pointer has type `&Shape`, which means "borrowed pointer to
|
||||||
immutable memory containing a `shape`". If, however, the type of that
|
immutable memory containing a `shape`". If, however, the type of that
|
||||||
pointer were `&mut Shape`, then the ref binding would be ill-typed.
|
pointer were `&mut Shape`, then the ref binding would be ill-typed.
|
||||||
Just as with unique boxes, the compiler will permit `ref` bindings
|
Just as with owned boxes, the compiler will permit `ref` bindings
|
||||||
into data owned by the stack frame even if the data are mutable,
|
into data owned by the stack frame even if the data are mutable,
|
||||||
but otherwise it requires that the data reside in immutable memory.
|
but otherwise it requires that the data reside in immutable memory.
|
||||||
|
|
||||||
# Returning borrowed pointers
|
# Returning borrowed pointers
|
||||||
|
|
||||||
So far, all of the examples we've looked at use borrowed pointers in a
|
So far, all of the examples we have looked at, use borrowed pointers in a
|
||||||
“downward” direction. That is, a method or code block creates a
|
“downward” direction. That is, a method or code block creates a
|
||||||
borrowed pointer, then uses it within the same scope. It is also
|
borrowed pointer, then uses it within the same scope. It is also
|
||||||
possible to return borrowed pointers as the result of a function, but
|
possible to return borrowed pointers as the result of a function, but
|
||||||
@ -509,7 +509,7 @@ guaranteed to refer to a distinct lifetime from the lifetimes of all
|
|||||||
other parameters.
|
other parameters.
|
||||||
|
|
||||||
Named lifetimes that appear in function signatures are conceptually
|
Named lifetimes that appear in function signatures are conceptually
|
||||||
the same as the other lifetimes we've seen before, but they are a bit
|
the same as the other lifetimes we have seen before, but they are a bit
|
||||||
abstract: they don’t refer to a specific expression within `get_x()`,
|
abstract: they don’t refer to a specific expression within `get_x()`,
|
||||||
but rather to some expression within the *caller of `get_x()`*. The
|
but rather to some expression within the *caller of `get_x()`*. The
|
||||||
lifetime `r` is actually a kind of *lifetime parameter*: it is defined
|
lifetime `r` is actually a kind of *lifetime parameter*: it is defined
|
||||||
@ -550,7 +550,7 @@ guarantees; in fact, it cannot guarantee that the pointer will remain
|
|||||||
valid at all once it returns, as the parameter `p` may or may not be
|
valid at all once it returns, as the parameter `p` may or may not be
|
||||||
live in the caller. Therefore, the compiler will report an error here.
|
live in the caller. Therefore, the compiler will report an error here.
|
||||||
|
|
||||||
In general, if you borrow a managed (or unique) box to create a
|
In general, if you borrow a managed (or owned) box to create a
|
||||||
borrowed pointer, the pointer will only be valid within the function
|
borrowed pointer, the pointer will only be valid within the function
|
||||||
and cannot be returned. This is why the typical way to return borrowed
|
and cannot be returned. This is why the typical way to return borrowed
|
||||||
pointers is to take borrowed pointers as input (the only other case in
|
pointers is to take borrowed pointers as input (the only other case in
|
||||||
|
207
doc/tutorial-container.md
Normal file
207
doc/tutorial-container.md
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
% Containers and iterators
|
||||||
|
|
||||||
|
# Containers
|
||||||
|
|
||||||
|
The container traits are defined in the `std::container` module.
|
||||||
|
|
||||||
|
## Unique and managed vectors
|
||||||
|
|
||||||
|
Vectors have `O(1)` indexing and removal from the end, along with `O(1)`
|
||||||
|
amortized insertion. Vectors are the most common container in Rust, and are
|
||||||
|
flexible enough to fit many use cases.
|
||||||
|
|
||||||
|
Vectors can also be sorted and used as efficient lookup tables with the
|
||||||
|
`std::vec::bsearch` function, if all the elements are inserted at one time and
|
||||||
|
deletions are unnecessary.
|
||||||
|
|
||||||
|
## Maps and sets
|
||||||
|
|
||||||
|
Maps are collections of unique keys with corresponding values, and sets are
|
||||||
|
just unique keys without a corresponding value. The `Map` and `Set` traits in
|
||||||
|
`std::container` define the basic interface.
|
||||||
|
|
||||||
|
The standard library provides three owned map/set types:
|
||||||
|
|
||||||
|
* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to
|
||||||
|
implement `Eq` and `Hash`
|
||||||
|
* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint`
|
||||||
|
* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys
|
||||||
|
to implement `TotalOrd`
|
||||||
|
|
||||||
|
These maps do not use managed pointers so they can be sent between tasks as
|
||||||
|
long as the key and value types are sendable. Neither the key or value type has
|
||||||
|
to be copyable.
|
||||||
|
|
||||||
|
The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
|
||||||
|
order.
|
||||||
|
|
||||||
|
Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
|
||||||
|
making the order of a set of keys in a given hash table randomized. Rust
|
||||||
|
provides a [SipHash](https://131002.net/siphash/) implementation for any type
|
||||||
|
implementing the `IterBytes` trait.
|
||||||
|
|
||||||
|
## Double-ended queues
|
||||||
|
|
||||||
|
The `extra::deque` module implements a double-ended queue with `O(1)` amortized
|
||||||
|
inserts and removals from both ends of the container. It also has `O(1)`
|
||||||
|
indexing like a vector. The contained elements are not required to be copyable,
|
||||||
|
and the queue will be sendable if the contained type is sendable.
|
||||||
|
|
||||||
|
## Priority queues
|
||||||
|
|
||||||
|
The `extra::priority_queue` module implements a queue ordered by a key. The
|
||||||
|
contained elements are not required to be copyable, and the queue will be
|
||||||
|
sendable if the contained type is sendable.
|
||||||
|
|
||||||
|
Insertions have `O(log n)` time complexity and checking or popping the largest
|
||||||
|
element is `O(1)`. Converting a vector to a priority queue can be done
|
||||||
|
in-place, and has `O(n)` complexity. A priority queue can also be converted to
|
||||||
|
a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
|
||||||
|
heapsort.
|
||||||
|
|
||||||
|
# Iterators
|
||||||
|
|
||||||
|
## Iteration protocol
|
||||||
|
|
||||||
|
The iteration protocol is defined by the `Iterator` trait in the
|
||||||
|
`std::iterator` module. The minimal implementation of the trait is a `next`
|
||||||
|
method, yielding the next element from an iterator object:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
/// An infinite stream of zeroes
|
||||||
|
struct ZeroStream;
|
||||||
|
|
||||||
|
impl Iterator<int> for ZeroStream {
|
||||||
|
fn next(&mut self) -> Option<int> {
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Reaching the end of the iterator is signalled by returning `None` instead of
|
||||||
|
`Some(item)`:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
/// A stream of N zeroes
|
||||||
|
struct ZeroStream {
|
||||||
|
priv remaining: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZeroStream {
|
||||||
|
fn new(n: uint) -> ZeroStream {
|
||||||
|
ZeroStream { remaining: n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator<int> for ZeroStream {
|
||||||
|
fn next(&mut self) -> Option<int> {
|
||||||
|
if self.remaining == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.remaining -= 1;
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## Container iterators
|
||||||
|
|
||||||
|
Containers implement iteration over the contained elements by returning an
|
||||||
|
iterator object. For example, vectors have four iterators available:
|
||||||
|
|
||||||
|
* `vector.iter()`, for immutable references to the elements
|
||||||
|
* `vector.mut_iter()`, for mutable references to the elements
|
||||||
|
* `vector.rev_iter()`, for immutable references to the elements in reverse order
|
||||||
|
* `vector.mut_rev_iter()`, for mutable references to the elements in reverse order
|
||||||
|
|
||||||
|
### Freezing
|
||||||
|
|
||||||
|
Unlike most other languages with external iterators, Rust has no *iterator
|
||||||
|
invalidation*. As long an iterator is still in scope, the compiler will prevent
|
||||||
|
modification of the container through another handle.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
let mut xs = [1, 2, 3];
|
||||||
|
{
|
||||||
|
let _it = xs.iter();
|
||||||
|
|
||||||
|
// the vector is frozen for this scope, the compiler will statically
|
||||||
|
// prevent modification
|
||||||
|
}
|
||||||
|
// the vector becomes unfrozen again at the end of the scope
|
||||||
|
~~~
|
||||||
|
|
||||||
|
These semantics are due to most container iterators being implemented with `&`
|
||||||
|
and `&mut`.
|
||||||
|
|
||||||
|
## Iterator adaptors
|
||||||
|
|
||||||
|
The `IteratorUtil` trait implements common algorithms as methods extending
|
||||||
|
every `Iterator` implementation. For example, the `fold` method will accumulate
|
||||||
|
the items yielded by an `Iterator` into a single value:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
let xs = [1, 9, 2, 3, 14, 12];
|
||||||
|
let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
|
||||||
|
assert_eq!(result, -41);
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Some adaptors return an adaptor object implementing the `Iterator` trait itself:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
let xs = [1, 9, 2, 3, 14, 12];
|
||||||
|
let ys = [5, 2, 1, 8];
|
||||||
|
let sum = xs.iter().chain_(ys.iter()).fold(0, |a, b| a + *b);
|
||||||
|
assert_eq!(sum, 57);
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Note that some adaptors like the `chain_` method above use a trailing
|
||||||
|
underscore to work around an issue with method resolve. The underscores will be
|
||||||
|
dropped when they become unnecessary.
|
||||||
|
|
||||||
|
## For loops
|
||||||
|
|
||||||
|
The `for` loop syntax is currently in transition, and will switch from the old
|
||||||
|
closure-based iteration protocol to iterator objects. For now, the `advance`
|
||||||
|
adaptor is required as a compatibility shim to use iterators with for loops.
|
||||||
|
|
||||||
|
~~~
|
||||||
|
let xs = [2, 3, 5, 7, 11, 13, 17];
|
||||||
|
|
||||||
|
// print out all the elements in the vector
|
||||||
|
for xs.iter().advance |x| {
|
||||||
|
println(x.to_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
// print out all but the first 3 elements in the vector
|
||||||
|
for xs.iter().skip(3).advance |x| {
|
||||||
|
println(x.to_str())
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
For loops are *often* used with a temporary iterator object, as above. They can
|
||||||
|
also advance the state of an iterator in a mutable location:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
let xs = [1, 2, 3, 4, 5];
|
||||||
|
let ys = ["foo", "bar", "baz", "foobar"];
|
||||||
|
|
||||||
|
// create an iterator yielding tuples of elements from both vectors
|
||||||
|
let mut it = xs.iter().zip(ys.iter());
|
||||||
|
|
||||||
|
// print out the pairs of elements up to (&3, &"baz")
|
||||||
|
for it.advance |(x, y)| {
|
||||||
|
println(fmt!("%d %s", *x, *y));
|
||||||
|
|
||||||
|
if *x == 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// yield and print the last pair from the iterator
|
||||||
|
println(fmt!("last: %?", it.next()));
|
||||||
|
|
||||||
|
// the iterator is now fully consumed
|
||||||
|
assert!(it.next().is_none());
|
||||||
|
~~~
|
@ -2,255 +2,269 @@
|
|||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Because Rust is a systems programming language, one of its goals is to
|
This tutorial will use the [snappy](https://code.google.com/p/snappy/)
|
||||||
interoperate well with C code.
|
compression/decompression library as an introduction to writing bindings for
|
||||||
|
foreign code. Rust is currently unable to call directly into a C++ library, but
|
||||||
|
snappy includes a C interface (documented in
|
||||||
|
[`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)).
|
||||||
|
|
||||||
We'll start with an example, which is a bit bigger than usual. We'll
|
The following is a minimal example of calling a foreign function which will compile if snappy is
|
||||||
go over it one piece at a time. This is a program that uses OpenSSL's
|
installed:
|
||||||
`SHA1` function to compute the hash of its first command-line
|
|
||||||
argument, which it then converts to a hexadecimal string and prints to
|
|
||||||
standard output. If you have the OpenSSL libraries installed, it
|
|
||||||
should compile and run without any extra effort.
|
|
||||||
|
|
||||||
~~~~ {.xfail-test}
|
~~~~ {.xfail-test}
|
||||||
extern mod std;
|
use std::libc::size_t;
|
||||||
use core::libc::c_uint;
|
|
||||||
|
|
||||||
extern mod crypto {
|
#[link_args = "-lsnappy"]
|
||||||
fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8;
|
extern {
|
||||||
}
|
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
|
||||||
|
|
||||||
fn as_hex(data: ~[u8]) -> ~str {
|
|
||||||
let mut acc = ~"";
|
|
||||||
for data.each |&byte| { acc += fmt!("%02x", byte as uint); }
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sha1(data: ~str) -> ~str {
|
|
||||||
unsafe {
|
|
||||||
let bytes = str::to_bytes(data);
|
|
||||||
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
|
|
||||||
vec::len(bytes) as c_uint,
|
|
||||||
ptr::null());
|
|
||||||
return as_hex(vec::from_buf(hash, 20));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
io::println(sha1(core::os::args()[1]));
|
let x = unsafe { snappy_max_compressed_length(100) };
|
||||||
|
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
# Foreign modules
|
The `extern` block is a list of function signatures in a foreign library, in this case with the
|
||||||
|
platform's C ABI. The `#[link_args]` attribute is used to instruct the linker to link against the
|
||||||
|
snappy library so the symbols are resolved.
|
||||||
|
|
||||||
Before we can call the `SHA1` function defined in the OpenSSL library, we have
|
Foreign functions are assumed to be unsafe so calls to them need to be wrapped with `unsafe {}` as a
|
||||||
to declare it. That is what this part of the program does:
|
promise to the compiler that everything contained within truly is safe. C libraries often expose
|
||||||
|
interfaces that aren't thread-safe, and almost any function that takes a pointer argument isn't
|
||||||
|
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
|
||||||
|
Rust's safe memory model.
|
||||||
|
|
||||||
|
When declaring the argument types to a foreign function, the Rust compiler will not check if the
|
||||||
|
declaration is correct, so specifying it correctly is part of keeping the binding correct at
|
||||||
|
runtime.
|
||||||
|
|
||||||
|
The `extern` block can be extended to cover the entire snappy API:
|
||||||
|
|
||||||
~~~~ {.xfail-test}
|
~~~~ {.xfail-test}
|
||||||
extern mod crypto {
|
use std::libc::{c_int, size_t};
|
||||||
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; }
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
An `extern` module declaration containing function signatures introduces the
|
#[link_args = "-lsnappy"]
|
||||||
functions listed as _foreign functions_. Foreign functions differ from regular
|
extern {
|
||||||
Rust functions in that they are implemented in some other language (usually C)
|
fn snappy_compress(input: *u8,
|
||||||
and called through Rust's foreign function interface (FFI). An extern module
|
input_length: size_t,
|
||||||
like this is called a foreign module, and implicitly tells the compiler to
|
compressed: *mut u8,
|
||||||
link with a library that contains the listed foreign functions, and has the
|
compressed_length: *mut size_t) -> c_int;
|
||||||
same name as the module.
|
fn snappy_uncompress(compressed: *u8,
|
||||||
|
compressed_length: size_t,
|
||||||
In this case, the Rust compiler changes the name `crypto` to a shared library
|
uncompressed: *mut u8,
|
||||||
name in a platform-specific way (`libcrypto.so` on Linux, for example),
|
uncompressed_length: *mut size_t) -> c_int;
|
||||||
searches for the shared library with that name, and links the library into the
|
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
|
||||||
program. If you want the module to have a different name from the actual
|
fn snappy_uncompressed_length(compressed: *u8,
|
||||||
library, you can use the `"link_name"` attribute, like:
|
compressed_length: size_t,
|
||||||
|
result: *mut size_t) -> c_int;
|
||||||
~~~~ {.xfail-test}
|
fn snappy_validate_compressed_buffer(compressed: *u8,
|
||||||
#[link_name = "crypto"]
|
compressed_length: size_t) -> c_int;
|
||||||
extern mod something {
|
|
||||||
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
|
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
# Creating a safe interface
|
||||||
|
|
||||||
|
The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts
|
||||||
|
like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe
|
||||||
|
internal details.
|
||||||
|
|
||||||
|
Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust
|
||||||
|
vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
|
||||||
|
length is number of elements currently contained, and the capacity is the total size in elements of
|
||||||
|
the allocated memory. The length is less than or equal to the capacity.
|
||||||
|
|
||||||
|
~~~~ {.xfail-test}
|
||||||
|
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
|
||||||
|
unsafe {
|
||||||
|
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
|
||||||
|
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
|
||||||
|
signature.
|
||||||
|
|
||||||
|
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
|
||||||
|
allocated to hold the output too.
|
||||||
|
|
||||||
|
The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum
|
||||||
|
required capacity to hold the compressed output. The vector can then be passed to the
|
||||||
|
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
|
||||||
|
the true length after compression for setting the length.
|
||||||
|
|
||||||
|
~~~~ {.xfail-test}
|
||||||
|
pub fn compress(src: &[u8]) -> ~[u8] {
|
||||||
|
unsafe {
|
||||||
|
let srclen = src.len() as size_t;
|
||||||
|
let psrc = vec::raw::to_ptr(src);
|
||||||
|
|
||||||
|
let mut dstlen = snappy_max_compressed_length(srclen);
|
||||||
|
let mut dst = vec::with_capacity(dstlen as uint);
|
||||||
|
let pdst = vec::raw::to_mut_ptr(dst);
|
||||||
|
|
||||||
|
snappy_compress(psrc, srclen, pdst, &mut dstlen);
|
||||||
|
vec::raw::set_len(&mut dst, dstlen as uint);
|
||||||
|
dst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Decompression is similar, because snappy stores the uncompressed size as part of the compression
|
||||||
|
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
|
||||||
|
|
||||||
|
~~~~ {.xfail-test}
|
||||||
|
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
|
||||||
|
unsafe {
|
||||||
|
let srclen = src.len() as size_t;
|
||||||
|
let psrc = vec::raw::to_ptr(src);
|
||||||
|
|
||||||
|
let mut dstlen: size_t = 0;
|
||||||
|
snappy_uncompressed_length(psrc, srclen, &mut dstlen);
|
||||||
|
|
||||||
|
let mut dst = vec::with_capacity(dstlen as uint);
|
||||||
|
let pdst = vec::raw::to_mut_ptr(dst);
|
||||||
|
|
||||||
|
if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
|
||||||
|
vec::raw::set_len(&mut dst, dstlen as uint);
|
||||||
|
Some(dst)
|
||||||
|
} else {
|
||||||
|
None // SNAPPY_INVALID_INPUT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
For reference, the examples used here are also available as an [library on
|
||||||
|
GitHub](https://github.com/thestinger/rust-snappy).
|
||||||
|
|
||||||
|
# Destructors
|
||||||
|
|
||||||
|
Foreign libraries often hand off ownership of resources to the calling code,
|
||||||
|
which should be wrapped in a destructor to provide safety and guarantee their
|
||||||
|
release.
|
||||||
|
|
||||||
|
A type with the same functionality as owned boxes can be implemented by
|
||||||
|
wrapping `malloc` and `free`:
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
use std::cast;
|
||||||
|
use std::libc::{c_void, size_t, malloc, free};
|
||||||
|
use std::ptr;
|
||||||
|
use std::unstable::intrinsics;
|
||||||
|
|
||||||
|
// a wrapper around the handle returned by the foreign code
|
||||||
|
pub struct Unique<T> {
|
||||||
|
priv ptr: *mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send> Unique<T> {
|
||||||
|
pub fn new(value: T) -> Unique<T> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
|
||||||
|
assert!(!ptr::is_null(ptr));
|
||||||
|
// `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
|
||||||
|
intrinsics::move_val_init(&mut *ptr, value);
|
||||||
|
Unique{ptr: ptr}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the 'r lifetime results in the same semantics as `&*x` with ~T
|
||||||
|
pub fn borrow<'r>(&'r self) -> &'r T {
|
||||||
|
unsafe { cast::copy_lifetime(self, &*self.ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// the 'r lifetime results in the same semantics as `&mut *x` with ~T
|
||||||
|
pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
|
||||||
|
unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl<T: Send> Drop for Unique<T> {
|
||||||
|
fn drop(&self) {
|
||||||
|
unsafe {
|
||||||
|
let x = intrinsics::init(); // dummy value to swap in
|
||||||
|
// moving the object out is needed to call the destructor
|
||||||
|
ptr::replace_ptr(self.ptr, x);
|
||||||
|
free(self.ptr as *c_void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A comparison between the built-in ~ and this reimplementation
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
let mut x = ~5;
|
||||||
|
*x = 10;
|
||||||
|
} // `x` is freed here
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut y = Unique::new(5);
|
||||||
|
*y.borrow_mut() = 10;
|
||||||
|
} // `y` is freed here
|
||||||
|
}
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
# Linking
|
||||||
|
|
||||||
|
In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an
|
||||||
|
`extern mod` block will pass `-lmodname` to the linker by default unless it has a `#[nolink]`
|
||||||
|
attribute applied.
|
||||||
|
|
||||||
|
# Unsafe blocks
|
||||||
|
|
||||||
|
Some operations, like dereferencing unsafe pointers or calling functions that have been marked
|
||||||
|
unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
|
||||||
|
the compiler that the unsafety does not leak out of the block.
|
||||||
|
|
||||||
|
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
|
||||||
|
this:
|
||||||
|
|
||||||
|
~~~~
|
||||||
|
unsafe fn kaboom(ptr: *int) -> int { *ptr }
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
This function can only be called from an `unsafe` block or another `unsafe` function.
|
||||||
|
|
||||||
# Foreign calling conventions
|
# Foreign calling conventions
|
||||||
|
|
||||||
Most foreign code is C code, which usually uses the `cdecl` calling
|
Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
|
||||||
convention, so that is what Rust uses by default when calling foreign
|
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
|
||||||
functions. Some foreign functions, most notably the Windows API, use other
|
conventions. Rust provides the `abi` attribute as a way to hint to the compiler which calling
|
||||||
calling conventions. Rust provides the `"abi"` attribute as a way to hint to
|
convention to use:
|
||||||
the compiler which calling convention to use:
|
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
#[abi = "stdcall"]
|
#[abi = "stdcall"]
|
||||||
extern mod kernel32 {
|
#[link_name = "kernel32"]
|
||||||
|
extern {
|
||||||
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
|
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
The `"abi"` attribute applies to a foreign module (it cannot be applied
|
The `abi` attribute applies to a foreign module (it cannot be applied to a single function within a
|
||||||
to a single function within a module), and must be either `"cdecl"`
|
module), and must be either `"cdecl"` or `"stdcall"`. The compiler may eventually support other
|
||||||
or `"stdcall"`. We may extend the compiler in the future to support other
|
|
||||||
calling conventions.
|
calling conventions.
|
||||||
|
|
||||||
# Unsafe pointers
|
# Interoperability with foreign code
|
||||||
|
|
||||||
The foreign `SHA1` function takes three arguments, and returns a pointer.
|
Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
|
||||||
|
A `#[packed]` attribute is available, which will lay out the struct members without padding.
|
||||||
|
However, there are currently no guarantees about the layout of an `enum`.
|
||||||
|
|
||||||
~~~~ {.xfail-test}
|
Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
|
||||||
# extern mod crypto {
|
object. However, they should not be manually created because they are managed by internal
|
||||||
fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
|
allocators. Borrowed pointers can safely be assumed to be non-nullable pointers directly to the
|
||||||
# }
|
type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so
|
||||||
~~~~
|
prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions
|
||||||
|
about them.
|
||||||
|
|
||||||
When declaring the argument types to a foreign function, the Rust
|
Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
|
||||||
compiler has no way to check whether your declaration is correct, so
|
`str` modules for working with C APIs. Strings are terminated with `\0` for interoperability with C,
|
||||||
you have to be careful. If you get the number or types of the
|
but it should not be assumed because a slice will not always be nul-terminated. Instead, the
|
||||||
arguments wrong, you're likely to cause a segmentation fault. Or,
|
`str::as_c_str` function should be used.
|
||||||
probably even worse, your code will work on one platform, but break on
|
|
||||||
another.
|
|
||||||
|
|
||||||
In this case, we declare that `SHA1` takes two `unsigned char*`
|
|
||||||
arguments and one `unsigned long`. The Rust equivalents are `*u8`
|
|
||||||
unsafe pointers and an `uint` (which, like `unsigned long`, is a
|
|
||||||
machine-word-sized type).
|
|
||||||
|
|
||||||
The standard library provides various functions to create unsafe pointers,
|
|
||||||
such as those in `core::cast`. Most of these functions have `unsafe` in their
|
|
||||||
name. You can dereference an unsafe pointer with the `*` operator, but use
|
|
||||||
caution: unlike Rust's other pointer types, unsafe pointers are completely
|
|
||||||
unmanaged, so they might point at invalid memory, or be null pointers.
|
|
||||||
|
|
||||||
# Unsafe blocks
|
|
||||||
|
|
||||||
The `sha1` function is the most obscure part of the program.
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
# pub mod crypto {
|
|
||||||
# pub fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out }
|
|
||||||
# }
|
|
||||||
# fn as_hex(data: ~[u8]) -> ~str { ~"hi" }
|
|
||||||
fn sha1(data: ~str) -> ~str {
|
|
||||||
unsafe {
|
|
||||||
let bytes = str::to_bytes(data);
|
|
||||||
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
|
|
||||||
vec::len(bytes), ptr::null());
|
|
||||||
return as_hex(vec::from_buf(hash, 20));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
First, what does the `unsafe` keyword at the top of the function
|
|
||||||
mean? `unsafe` is a block modifier—it declares the block following it
|
|
||||||
to be known to be unsafe.
|
|
||||||
|
|
||||||
Some operations, like dereferencing unsafe pointers or calling
|
|
||||||
functions that have been marked unsafe, are only allowed inside unsafe
|
|
||||||
blocks. With the `unsafe` keyword, you're telling the compiler 'I know
|
|
||||||
what I'm doing'. The main motivation for such an annotation is that
|
|
||||||
when you have a memory error (and you will, if you're using unsafe
|
|
||||||
constructs), you have some idea where to look—it will most likely be
|
|
||||||
caused by some unsafe code.
|
|
||||||
|
|
||||||
Unsafe blocks isolate unsafety. Unsafe functions, on the other hand,
|
|
||||||
advertise it to the world. An unsafe function is written like this:
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
unsafe fn kaboom() { ~"I'm harmless!"; }
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
This function can only be called from an `unsafe` block or another
|
|
||||||
`unsafe` function.
|
|
||||||
|
|
||||||
# Pointer fiddling
|
|
||||||
|
|
||||||
The standard library defines a number of helper functions for dealing
|
|
||||||
with unsafe data, casting between types, and generally subverting
|
|
||||||
Rust's safety mechanisms.
|
|
||||||
|
|
||||||
Let's look at our `sha1` function again.
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
# pub mod crypto {
|
|
||||||
# pub fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out }
|
|
||||||
# }
|
|
||||||
# fn as_hex(data: ~[u8]) -> ~str { ~"hi" }
|
|
||||||
# fn x(data: ~str) -> ~str {
|
|
||||||
# unsafe {
|
|
||||||
let bytes = str::to_bytes(data);
|
|
||||||
let hash = crypto::SHA1(vec::raw::to_ptr(bytes),
|
|
||||||
vec::len(bytes), ptr::null());
|
|
||||||
return as_hex(vec::from_buf(hash, 20));
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The `str::to_bytes` function is perfectly safe: it converts a string to a
|
|
||||||
`~[u8]`. The program then feeds this byte array to `vec::raw::to_ptr`, which
|
|
||||||
returns an unsafe pointer to its contents.
|
|
||||||
|
|
||||||
This pointer will become invalid at the end of the scope in which the vector
|
|
||||||
it points to (`bytes`) is valid, so you should be very careful how you use
|
|
||||||
it. In this case, the local variable `bytes` outlives the pointer, so we're
|
|
||||||
good.
|
|
||||||
|
|
||||||
Passing a null pointer as the third argument to `SHA1` makes it use a
|
|
||||||
static buffer, and thus save us the effort of allocating memory
|
|
||||||
ourselves. `ptr::null` is a generic function that, in this case, returns an
|
|
||||||
unsafe null pointer of type `*u8`. (Rust generics are awesome
|
|
||||||
like that: they can take the right form depending on the type that they
|
|
||||||
are expected to return.)
|
|
||||||
|
|
||||||
Finally, `vec::from_buf` builds up a new `~[u8]` from the
|
|
||||||
unsafe pointer that `SHA1` returned. SHA1 digests are always
|
|
||||||
twenty bytes long, so we can pass `20` for the length of the new
|
|
||||||
vector.
|
|
||||||
|
|
||||||
# Passing structures
|
|
||||||
|
|
||||||
C functions often take pointers to structs as arguments. Since Rust
|
|
||||||
`struct`s are binary-compatible with C structs, Rust programs can call
|
|
||||||
such functions directly.
|
|
||||||
|
|
||||||
This program uses the POSIX function `gettimeofday` to get a
|
|
||||||
microsecond-resolution timer.
|
|
||||||
|
|
||||||
~~~~
|
|
||||||
extern mod std;
|
|
||||||
use core::libc::c_ulonglong;
|
|
||||||
|
|
||||||
struct timeval {
|
|
||||||
tv_sec: c_ulonglong,
|
|
||||||
tv_usec: c_ulonglong
|
|
||||||
}
|
|
||||||
|
|
||||||
#[nolink]
|
|
||||||
extern mod lib_c {
|
|
||||||
fn gettimeofday(tv: *mut timeval, tz: *()) -> i32;
|
|
||||||
}
|
|
||||||
fn unix_time_in_microseconds() -> u64 {
|
|
||||||
unsafe {
|
|
||||||
let mut x = timeval {
|
|
||||||
tv_sec: 0 as c_ulonglong,
|
|
||||||
tv_usec: 0 as c_ulonglong
|
|
||||||
};
|
|
||||||
lib_c::gettimeofday(&mut x, ptr::null());
|
|
||||||
return (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# fn main() { assert!(fmt!("%?", unix_time_in_microseconds()) != ~""); }
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The `#[nolink]` attribute indicates that there's no foreign library to
|
|
||||||
link in. The standard C library is already linked with Rust programs.
|
|
||||||
|
|
||||||
In C, a `timeval` is a struct with two 32-bit integer fields. Thus, we
|
|
||||||
define a `struct` type with the same contents, and declare
|
|
||||||
`gettimeofday` to take a pointer to such a `struct`.
|
|
||||||
|
|
||||||
This program does not use the second argument to `gettimeofday` (the time
|
|
||||||
zone), so the `extern mod` declaration for it simply declares this argument
|
|
||||||
to be a pointer to the unit type (written `()`). Since all null pointers have
|
|
||||||
the same representation regardless of their referent type, this is safe.
|
|
||||||
|
|
||||||
|
The standard library includes type aliases and function definitions for the C standard library in
|
||||||
|
the `libc` module, and Rust links against `libc` and `libm` by default.
|
||||||
|
@ -13,7 +13,8 @@ doing nothing otherwise:
|
|||||||
~~~~
|
~~~~
|
||||||
# enum t { special_a(uint), special_b(uint) };
|
# enum t { special_a(uint), special_b(uint) };
|
||||||
# fn f() -> uint {
|
# fn f() -> uint {
|
||||||
# let input_1 = special_a(0), input_2 = special_a(0);
|
# let input_1 = special_a(0);
|
||||||
|
# let input_2 = special_a(0);
|
||||||
match input_1 {
|
match input_1 {
|
||||||
special_a(x) => { return x; }
|
special_a(x) => { return x; }
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -38,7 +39,8 @@ the pattern in the above code:
|
|||||||
~~~~
|
~~~~
|
||||||
# enum t { special_a(uint), special_b(uint) };
|
# enum t { special_a(uint), special_b(uint) };
|
||||||
# fn f() -> uint {
|
# fn f() -> uint {
|
||||||
# let input_1 = special_a(0), input_2 = special_a(0);
|
# let input_1 = special_a(0);
|
||||||
|
# let input_2 = special_a(0);
|
||||||
macro_rules! early_return(
|
macro_rules! early_return(
|
||||||
($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`
|
($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`
|
||||||
match $inp {
|
match $inp {
|
||||||
@ -155,7 +157,8 @@ instead of `*` to mean "at least one".
|
|||||||
~~~~
|
~~~~
|
||||||
# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};
|
# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};
|
||||||
# fn f() -> uint {
|
# fn f() -> uint {
|
||||||
# let input_1 = special_a(0), input_2 = special_a(0);
|
# let input_1 = special_a(0);
|
||||||
|
# let input_2 = special_a(0);
|
||||||
macro_rules! early_return(
|
macro_rules! early_return(
|
||||||
($inp:expr, [ $($sp:ident)|+ ]) => (
|
($inp:expr, [ $($sp:ident)|+ ]) => (
|
||||||
match $inp {
|
match $inp {
|
||||||
@ -223,7 +226,7 @@ match x {
|
|||||||
// complicated stuff goes here
|
// complicated stuff goes here
|
||||||
return result + val;
|
return result + val;
|
||||||
},
|
},
|
||||||
_ => fail!(~"Didn't get good_2")
|
_ => fail!("Didn't get good_2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return 0 // default value
|
_ => return 0 // default value
|
||||||
@ -265,7 +268,7 @@ macro_rules! biased_match (
|
|||||||
biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
|
biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
|
||||||
binds g1, val )
|
binds g1, val )
|
||||||
biased_match!((g1.body) ~ (good_2(result) )
|
biased_match!((g1.body) ~ (good_2(result) )
|
||||||
else { fail!(~"Didn't get good_2") };
|
else { fail!("Didn't get good_2") };
|
||||||
binds result )
|
binds result )
|
||||||
// complicated stuff goes here
|
// complicated stuff goes here
|
||||||
return result + val;
|
return result + val;
|
||||||
@ -366,7 +369,7 @@ macro_rules! biased_match (
|
|||||||
# fn f(x: t1) -> uint {
|
# fn f(x: t1) -> uint {
|
||||||
biased_match!(
|
biased_match!(
|
||||||
(x) ~ (good_1(g1, val)) else { return 0 };
|
(x) ~ (good_1(g1, val)) else { return 0 };
|
||||||
(g1.body) ~ (good_2(result) ) else { fail!(~"Didn't get good_2") };
|
(g1.body) ~ (good_2(result) ) else { fail!("Didn't get good_2") };
|
||||||
binds val, result )
|
binds val, result )
|
||||||
// complicated stuff goes here
|
// complicated stuff goes here
|
||||||
return result + val;
|
return result + val;
|
||||||
@ -402,4 +405,3 @@ tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
|
|||||||
states, invoking `trace_macros!(true)` will automatically print those
|
states, invoking `trace_macros!(true)` will automatically print those
|
||||||
intermediate states out, and passing the flag `--pretty expanded` as a
|
intermediate states out, and passing the flag `--pretty expanded` as a
|
||||||
command-line argument to the compiler will show the result of expansion.
|
command-line argument to the compiler will show the result of expansion.
|
||||||
|
|
||||||
|
@ -2,86 +2,77 @@
|
|||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
The designers of Rust designed the language from the ground up to support pervasive
|
Rust provides safe concurrency through a combination
|
||||||
and safe concurrency through lightweight, memory-isolated tasks and
|
of lightweight, memory-isolated tasks and message passing.
|
||||||
message passing.
|
This tutorial will describe the concurrency model in Rust, how it
|
||||||
|
relates to the Rust type system, and introduce
|
||||||
|
the fundamental library abstractions for constructing concurrent programs.
|
||||||
|
|
||||||
Rust tasks are not the same as traditional threads: rather, they are more like
|
Rust tasks are not the same as traditional threads: rather,
|
||||||
_green threads_. The Rust runtime system schedules tasks cooperatively onto a
|
they are considered _green threads_, lightweight units of execution that the Rust
|
||||||
small number of operating system threads. Because tasks are significantly
|
runtime schedules cooperatively onto a small number of operating system threads.
|
||||||
|
On a multi-core system Rust tasks will be scheduled in parallel by default.
|
||||||
|
Because tasks are significantly
|
||||||
cheaper to create than traditional threads, Rust can create hundreds of
|
cheaper to create than traditional threads, Rust can create hundreds of
|
||||||
thousands of concurrent tasks on a typical 32-bit system.
|
thousands of concurrent tasks on a typical 32-bit system.
|
||||||
|
In general, all Rust code executes inside a task, including the `main` function.
|
||||||
|
|
||||||
Tasks provide failure isolation and recovery. When an exception occurs in Rust
|
In order to make efficient use of memory Rust tasks have dynamically sized stacks.
|
||||||
code (as a result of an explicit call to `fail!()`, an assertion failure, or
|
A task begins its life with a small
|
||||||
another invalid operation), the runtime system destroys the entire
|
amount of stack space (currently in the low thousands of bytes, depending on
|
||||||
|
platform), and acquires more stack as needed.
|
||||||
|
Unlike in languages such as C, a Rust task cannot accidentally write to
|
||||||
|
memory beyond the end of the stack, causing crashes or worse.
|
||||||
|
|
||||||
|
Tasks provide failure isolation and recovery. When a fatal error occurs in Rust
|
||||||
|
code as a result of an explicit call to `fail!()`, an assertion failure, or
|
||||||
|
another invalid operation, the runtime system destroys the entire
|
||||||
task. Unlike in languages such as Java and C++, there is no way to `catch` an
|
task. Unlike in languages such as Java and C++, there is no way to `catch` an
|
||||||
exception. Instead, tasks may monitor each other for failure.
|
exception. Instead, tasks may monitor each other for failure.
|
||||||
|
|
||||||
Rust tasks have dynamically sized stacks. A task begins its life with a small
|
|
||||||
amount of stack space (currently in the low thousands of bytes, depending on
|
|
||||||
platform), and acquires more stack as needed. Unlike in languages such as C, a
|
|
||||||
Rust task cannot run off the end of the stack. However, tasks do have a stack
|
|
||||||
budget. If a Rust task exceeds its stack budget, then it will fail safely:
|
|
||||||
with a checked exception.
|
|
||||||
|
|
||||||
Tasks use Rust's type system to provide strong memory safety guarantees. In
|
Tasks use Rust's type system to provide strong memory safety guarantees. In
|
||||||
particular, the type system guarantees that tasks cannot share mutable state
|
particular, the type system guarantees that tasks cannot share mutable state
|
||||||
with each other. Tasks communicate with each other by transferring _owned_
|
with each other. Tasks communicate with each other by transferring _owned_
|
||||||
data through the global _exchange heap_.
|
data through the global _exchange heap_.
|
||||||
|
|
||||||
This tutorial explains the basics of tasks and communication in Rust,
|
|
||||||
explores some typical patterns in concurrent Rust code, and finally
|
|
||||||
discusses some of the more unusual synchronization types in the standard
|
|
||||||
library.
|
|
||||||
|
|
||||||
> ***Warning:*** This tutorial is incomplete
|
|
||||||
|
|
||||||
## A note about the libraries
|
## A note about the libraries
|
||||||
|
|
||||||
While Rust's type system provides the building blocks needed for safe
|
While Rust's type system provides the building blocks needed for safe
|
||||||
and efficient tasks, all of the task functionality itself is implemented
|
and efficient tasks, all of the task functionality itself is implemented
|
||||||
in the core and standard libraries, which are still under development
|
in the standard and extra libraries, which are still under development
|
||||||
and do not always present a consistent interface.
|
and do not always present a consistent or complete interface.
|
||||||
|
|
||||||
In particular, there are currently two independent modules that provide a
|
|
||||||
message passing interface to Rust code: `core::comm` and `core::pipes`.
|
|
||||||
`core::comm` is an older, less efficient system that is being phased out in
|
|
||||||
favor of `pipes`. At some point, we will remove the existing `core::comm` API
|
|
||||||
and move the user-facing portions of `core::pipes` to `core::comm`. In this
|
|
||||||
tutorial, we discuss `pipes` and ignore the `comm` API.
|
|
||||||
|
|
||||||
For your reference, these are the standard modules involved in Rust
|
For your reference, these are the standard modules involved in Rust
|
||||||
concurrency at this writing.
|
concurrency at this writing:
|
||||||
|
|
||||||
* [`core::task`] - All code relating to tasks and task scheduling
|
* [`std::task`] - All code relating to tasks and task scheduling,
|
||||||
* [`core::comm`] - The deprecated message passing API
|
* [`std::comm`] - The message passing interface,
|
||||||
* [`core::pipes`] - The new message passing infrastructure and API
|
* [`std::pipes`] - The underlying messaging infrastructure,
|
||||||
* [`std::comm`] - Higher level messaging types based on `core::pipes`
|
* [`extra::comm`] - Additional messaging types based on `std::pipes`,
|
||||||
* [`std::sync`] - More exotic synchronization tools, including locks
|
* [`extra::sync`] - More exotic synchronization tools, including locks,
|
||||||
* [`std::arc`] - The ARC (atomic reference counted) type, for safely sharing
|
* [`extra::arc`] - The ARC (atomically reference counted) type,
|
||||||
immutable data
|
for safely sharing immutable data,
|
||||||
* [`std::par`] - Some basic tools for implementing parallel algorithms
|
* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time.
|
||||||
|
|
||||||
[`core::task`]: core/task.html
|
[`std::task`]: std/task.html
|
||||||
[`core::comm`]: core/comm.html
|
|
||||||
[`core::pipes`]: core/pipes.html
|
|
||||||
[`std::comm`]: std/comm.html
|
[`std::comm`]: std/comm.html
|
||||||
[`std::sync`]: std/sync.html
|
[`std::pipes`]: std/pipes.html
|
||||||
[`std::arc`]: std/arc.html
|
[`extra::comm`]: extra/comm.html
|
||||||
[`std::par`]: std/par.html
|
[`extra::sync`]: extra/sync.html
|
||||||
|
[`extra::arc`]: extra/arc.html
|
||||||
|
[`extra::future`]: extra/future.html
|
||||||
|
|
||||||
# Basics
|
# Basics
|
||||||
|
|
||||||
The programming interface for creating and managing tasks lives
|
The programming interface for creating and managing tasks lives
|
||||||
in the `task` module of the `core` library, and is thus available to all
|
in the `task` module of the `std` library, and is thus available to all
|
||||||
Rust code by default. At its simplest, creating a task is a matter of
|
Rust code by default. At its simplest, creating a task is a matter of
|
||||||
calling the `spawn` function with a closure argument. `spawn` executes the
|
calling the `spawn` function with a closure argument. `spawn` executes the
|
||||||
closure in the new task.
|
closure in the new task.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::io::println;
|
# use std::io::println;
|
||||||
use core::task::spawn;
|
# use std::task::spawn;
|
||||||
|
|
||||||
// Print something profound in a different task using a named function
|
// Print something profound in a different task using a named function
|
||||||
fn print_message() { println("I am running in a different task!"); }
|
fn print_message() { println("I am running in a different task!"); }
|
||||||
@ -99,7 +90,7 @@ do spawn {
|
|||||||
In Rust, there is nothing special about creating tasks: a task is not a
|
In Rust, there is nothing special about creating tasks: a task is not a
|
||||||
concept that appears in the language semantics. Instead, Rust's type system
|
concept that appears in the language semantics. Instead, Rust's type system
|
||||||
provides all the tools necessary to implement safe concurrency: particularly,
|
provides all the tools necessary to implement safe concurrency: particularly,
|
||||||
_owned types_. The language leaves the implementation details to the core
|
_owned types_. The language leaves the implementation details to the standard
|
||||||
library.
|
library.
|
||||||
|
|
||||||
The `spawn` function has a very simple type signature: `fn spawn(f:
|
The `spawn` function has a very simple type signature: `fn spawn(f:
|
||||||
@ -110,8 +101,8 @@ execution. Like any closure, the function passed to `spawn` may capture
|
|||||||
an environment that it carries across tasks.
|
an environment that it carries across tasks.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::io::println;
|
# use std::io::println;
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
# fn generate_task_number() -> int { 0 }
|
# fn generate_task_number() -> int { 0 }
|
||||||
// Generate some state locally
|
// Generate some state locally
|
||||||
let child_task_number = generate_task_number();
|
let child_task_number = generate_task_number();
|
||||||
@ -127,8 +118,9 @@ in parallel. Thus, on a multicore machine, running the following code
|
|||||||
should interleave the output in vaguely random order.
|
should interleave the output in vaguely random order.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::io::print;
|
# use std::io::print;
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
|
# use std::int;
|
||||||
|
|
||||||
for int::range(0, 20) |child_task_number| {
|
for int::range(0, 20) |child_task_number| {
|
||||||
do spawn {
|
do spawn {
|
||||||
@ -156,8 +148,8 @@ endpoint. Consider the following example of calculating two results
|
|||||||
concurrently:
|
concurrently:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
use core::task::spawn;
|
# use std::task::spawn;
|
||||||
use core::comm::{stream, Port, Chan};
|
# use std::comm::{stream, Port, Chan};
|
||||||
|
|
||||||
let (port, chan): (Port<int>, Chan<int>) = stream();
|
let (port, chan): (Port<int>, Chan<int>) = stream();
|
||||||
|
|
||||||
@ -178,7 +170,7 @@ stream for sending and receiving integers (the left-hand side of the `let`,
|
|||||||
a tuple into its component parts).
|
a tuple into its component parts).
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::comm::{stream, Chan, Port};
|
# use std::comm::{stream, Chan, Port};
|
||||||
let (port, chan): (Port<int>, Chan<int>) = stream();
|
let (port, chan): (Port<int>, Chan<int>) = stream();
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
@ -187,8 +179,8 @@ which will wait to receive the data on the port. The next statement
|
|||||||
spawns the child task.
|
spawns the child task.
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
# use core::comm::stream;
|
# use std::comm::stream;
|
||||||
# fn some_expensive_computation() -> int { 42 }
|
# fn some_expensive_computation() -> int { 42 }
|
||||||
# let (port, chan) = stream();
|
# let (port, chan) = stream();
|
||||||
do spawn || {
|
do spawn || {
|
||||||
@ -208,7 +200,7 @@ computation, then waits for the child's result to arrive on the
|
|||||||
port:
|
port:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::comm::{stream};
|
# use std::comm::{stream};
|
||||||
# fn some_other_expensive_computation() {}
|
# fn some_other_expensive_computation() {}
|
||||||
# let (port, chan) = stream::<int>();
|
# let (port, chan) = stream::<int>();
|
||||||
# chan.send(0);
|
# chan.send(0);
|
||||||
@ -223,8 +215,8 @@ example needed to compute multiple results across a number of tasks? The
|
|||||||
following program is ill-typed:
|
following program is ill-typed:
|
||||||
|
|
||||||
~~~ {.xfail-test}
|
~~~ {.xfail-test}
|
||||||
# use core::task::{spawn};
|
# use std::task::{spawn};
|
||||||
# use core::comm::{stream, Port, Chan};
|
# use std::comm::{stream, Port, Chan};
|
||||||
# fn some_expensive_computation() -> int { 42 }
|
# fn some_expensive_computation() -> int { 42 }
|
||||||
let (port, chan) = stream();
|
let (port, chan) = stream();
|
||||||
|
|
||||||
@ -243,11 +235,12 @@ Instead we can use a `SharedChan`, a type that allows a single
|
|||||||
`Chan` to be shared by multiple senders.
|
`Chan` to be shared by multiple senders.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
use core::comm::{stream, SharedChan};
|
# use std::comm::{stream, SharedChan};
|
||||||
|
# use std::uint;
|
||||||
|
|
||||||
let (port, chan) = stream();
|
let (port, chan) = stream();
|
||||||
let chan = SharedChan(chan);
|
let chan = SharedChan::new(chan);
|
||||||
|
|
||||||
for uint::range(0, 3) |init_val| {
|
for uint::range(0, 3) |init_val| {
|
||||||
// Create a new channel handle to distribute to the child task
|
// Create a new channel handle to distribute to the child task
|
||||||
@ -276,8 +269,9 @@ illustrate the point. For reference, written with multiple streams, it
|
|||||||
might look like the example below.
|
might look like the example below.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
# use core::comm::stream;
|
# use std::comm::stream;
|
||||||
|
# use std::vec;
|
||||||
|
|
||||||
// Create a vector of ports, one for each child task
|
// Create a vector of ports, one for each child task
|
||||||
let ports = do vec::from_fn(3) |init_val| {
|
let ports = do vec::from_fn(3) |init_val| {
|
||||||
@ -289,10 +283,137 @@ let ports = do vec::from_fn(3) |init_val| {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Wait on each port, accumulating the results
|
// Wait on each port, accumulating the results
|
||||||
let result = ports.foldl(0, |accum, port| *accum + port.recv() );
|
let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
|
||||||
# fn some_expensive_computation(_i: uint) -> int { 42 }
|
# fn some_expensive_computation(_i: uint) -> int { 42 }
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
## Backgrounding computations: Futures
|
||||||
|
With `extra::future`, rust has a mechanism for requesting a computation and getting the result
|
||||||
|
later.
|
||||||
|
|
||||||
|
The basic example below illustrates this.
|
||||||
|
~~~
|
||||||
|
# fn make_a_sandwich() {};
|
||||||
|
fn fib(n: uint) -> uint {
|
||||||
|
// lengthy computation returning an uint
|
||||||
|
12586269025
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut delayed_fib = extra::future::spawn (|| fib(50) );
|
||||||
|
make_a_sandwich();
|
||||||
|
println(fmt!("fib(50) = %?", delayed_fib.get()))
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The call to `future::spawn` returns immediately a `future` object regardless of how long it
|
||||||
|
takes to run `fib(50)`. You can then make yourself a sandwich while the computation of `fib` is
|
||||||
|
running. The result of the execution of the method is obtained by calling `get` on the future.
|
||||||
|
This call will block until the value is available (*i.e.* the computation is complete). Note that
|
||||||
|
the future needs to be mutable so that it can save the result for next time `get` is called.
|
||||||
|
|
||||||
|
Here is another example showing how futures allow you to background computations. The workload will
|
||||||
|
be distributed on the available cores.
|
||||||
|
~~~
|
||||||
|
# use std::vec;
|
||||||
|
# use std::uint;
|
||||||
|
fn partial_sum(start: uint) -> f64 {
|
||||||
|
let mut local_sum = 0f64;
|
||||||
|
for uint::range(start*100000, (start+1)*100000) |num| {
|
||||||
|
local_sum += (num as f64 + 1.0).pow(&-2.0);
|
||||||
|
}
|
||||||
|
local_sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut futures = vec::from_fn(1000, |ind| do extra::future::spawn { partial_sum(ind) });
|
||||||
|
|
||||||
|
let mut final_res = 0f64;
|
||||||
|
for futures.mut_iter().advance |ft| {
|
||||||
|
final_res += ft.get();
|
||||||
|
}
|
||||||
|
println(fmt!("π^2/6 is not far from : %?", final_res));
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## Sharing immutable data without copy: ARC
|
||||||
|
|
||||||
|
To share immutable data between tasks, a first approach would be to only use pipes as we have seen
|
||||||
|
previously. A copy of the data to share would then be made for each task. In some cases, this would
|
||||||
|
add up to a significant amount of wasted memory and would require copying the same data more than
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
To tackle this issue, one can use an Atomically Reference Counted wrapper (`ARC`) as implemented in
|
||||||
|
the `extra` library of Rust. With an ARC, the data will no longer be copied for each task. The ARC
|
||||||
|
acts as a reference to the shared data and only this reference is shared and cloned.
|
||||||
|
|
||||||
|
Here is a small example showing how to use ARCs. We wish to run concurrently several computations on
|
||||||
|
a single large vector of floats. Each task needs the full vector to perform its duty.
|
||||||
|
~~~
|
||||||
|
# use std::vec;
|
||||||
|
# use std::uint;
|
||||||
|
# use std::rand;
|
||||||
|
use extra::arc::ARC;
|
||||||
|
|
||||||
|
fn pnorm(nums: &~[float], p: uint) -> float {
|
||||||
|
nums.iter().fold(0.0, |a,b| a+(*b).pow(&(p as float)) ).pow(&(1f / (p as float)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let numbers = vec::from_fn(1000000, |_| rand::random::<float>());
|
||||||
|
println(fmt!("Inf-norm = %?", *numbers.iter().max().unwrap()));
|
||||||
|
|
||||||
|
let numbers_arc = ARC(numbers);
|
||||||
|
|
||||||
|
for uint::range(1,10) |num| {
|
||||||
|
let (port, chan) = stream();
|
||||||
|
chan.send(numbers_arc.clone());
|
||||||
|
|
||||||
|
do spawn {
|
||||||
|
let local_arc : ARC<~[float]> = port.recv();
|
||||||
|
let task_numbers = local_arc.get();
|
||||||
|
println(fmt!("%u-norm = %?", num, pnorm(task_numbers, num)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The function `pnorm` performs a simple computation on the vector (it computes the sum of its items
|
||||||
|
at the power given as argument and takes the inverse power of this value). The ARC on the vector is
|
||||||
|
created by the line
|
||||||
|
~~~
|
||||||
|
# use extra::arc::ARC;
|
||||||
|
# use std::vec;
|
||||||
|
# use std::rand;
|
||||||
|
# let numbers = vec::from_fn(1000000, |_| rand::random::<float>());
|
||||||
|
let numbers_arc=ARC(numbers);
|
||||||
|
~~~
|
||||||
|
and a clone of it is sent to each task
|
||||||
|
~~~
|
||||||
|
# use extra::arc::ARC;
|
||||||
|
# use std::vec;
|
||||||
|
# use std::rand;
|
||||||
|
# let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||||
|
# let numbers_arc = ARC(numbers);
|
||||||
|
# let (port, chan) = stream();
|
||||||
|
chan.send(numbers_arc.clone());
|
||||||
|
~~~
|
||||||
|
copying only the wrapper and not its contents.
|
||||||
|
|
||||||
|
Each task recovers the underlying data by
|
||||||
|
~~~
|
||||||
|
# use extra::arc::ARC;
|
||||||
|
# use std::vec;
|
||||||
|
# use std::rand;
|
||||||
|
# let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||||
|
# let numbers_arc=ARC(numbers);
|
||||||
|
# let (port, chan) = stream();
|
||||||
|
# chan.send(numbers_arc.clone());
|
||||||
|
# let local_arc : ARC<~[float]> = port.recv();
|
||||||
|
let task_numbers = local_arc.get();
|
||||||
|
~~~
|
||||||
|
and can use it as if it were local.
|
||||||
|
|
||||||
|
The `arc` module also implements ARCs around mutable data that are not covered here.
|
||||||
|
|
||||||
# Handling task failure
|
# Handling task failure
|
||||||
|
|
||||||
Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
|
Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
|
||||||
@ -308,7 +429,8 @@ All tasks are, by default, _linked_ to each other. That means that the fates
|
|||||||
of all tasks are intertwined: if one fails, so do all the others.
|
of all tasks are intertwined: if one fails, so do all the others.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
|
# use std::task;
|
||||||
# fn do_some_work() { loop { task::yield() } }
|
# fn do_some_work() { loop { task::yield() } }
|
||||||
# do task::try {
|
# do task::try {
|
||||||
// Create a child task that fails
|
// Create a child task that fails
|
||||||
@ -330,13 +452,14 @@ field (representing a successful result) or an `Err` result (representing
|
|||||||
termination with an error).
|
termination with an error).
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
# use std::task;
|
||||||
# fn some_condition() -> bool { false }
|
# fn some_condition() -> bool { false }
|
||||||
# fn calculate_result() -> int { 0 }
|
# fn calculate_result() -> int { 0 }
|
||||||
let result: Result<int, ()> = do task::try {
|
let result: Result<int, ()> = do task::try {
|
||||||
if some_condition() {
|
if some_condition() {
|
||||||
calculate_result()
|
calculate_result()
|
||||||
} else {
|
} else {
|
||||||
fail!(~"oops!");
|
fail!("oops!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -348,7 +471,7 @@ enum. If the child task terminates successfully, `try` will
|
|||||||
return an `Ok` result; if the child task fails, `try` will return
|
return an `Ok` result; if the child task fails, `try` will return
|
||||||
an `Error` result.
|
an `Error` result.
|
||||||
|
|
||||||
[`Result`]: core/result.html
|
[`Result`]: std/result.html
|
||||||
|
|
||||||
> ***Note:*** A failed task does not currently produce a useful error
|
> ***Note:*** A failed task does not currently produce a useful error
|
||||||
> value (`try` always returns `Err(())`). In the
|
> value (`try` always returns `Err(())`). In the
|
||||||
@ -358,7 +481,7 @@ an `Error` result.
|
|||||||
TODO: Need discussion of `future_result` in order to make failure
|
TODO: Need discussion of `future_result` in order to make failure
|
||||||
modes useful.
|
modes useful.
|
||||||
|
|
||||||
But not all failure is created equal. In some cases you might need to
|
But not all failures are created equal. In some cases you might need to
|
||||||
abort the entire program (perhaps you're writing an assert which, if
|
abort the entire program (perhaps you're writing an assert which, if
|
||||||
it trips, indicates an unrecoverable logic error); in other cases you
|
it trips, indicates an unrecoverable logic error); in other cases you
|
||||||
might want to contain the failure at a certain boundary (perhaps a
|
might want to contain the failure at a certain boundary (perhaps a
|
||||||
@ -372,10 +495,11 @@ By default, task failure is _bidirectionally linked_, which means that if
|
|||||||
either task fails, it kills the other one.
|
either task fails, it kills the other one.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
# use std::task;
|
||||||
# fn sleep_forever() { loop { task::yield() } }
|
# fn sleep_forever() { loop { task::yield() } }
|
||||||
# do task::try {
|
# do task::try {
|
||||||
do task::spawn {
|
do spawn {
|
||||||
do task::spawn {
|
do spawn {
|
||||||
fail!(); // All three tasks will fail.
|
fail!(); // All three tasks will fail.
|
||||||
}
|
}
|
||||||
sleep_forever(); // Will get woken up by force, then fail
|
sleep_forever(); // Will get woken up by force, then fail
|
||||||
@ -392,8 +516,9 @@ internally, with additional logic to wait for the child task to finish
|
|||||||
before returning. Hence:
|
before returning. Hence:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
# use core::comm::{stream, Chan, Port};
|
# use std::comm::{stream, Chan, Port};
|
||||||
# use core::task::{spawn, try};
|
# use std::task::{spawn, try};
|
||||||
|
# use std::task;
|
||||||
# fn sleep_forever() { loop { task::yield() } }
|
# fn sleep_forever() { loop { task::yield() } }
|
||||||
# do task::try {
|
# do task::try {
|
||||||
let (receiver, sender): (Port<int>, Chan<int>) = stream();
|
let (receiver, sender): (Port<int>, Chan<int>) = stream();
|
||||||
@ -421,6 +546,7 @@ Supervised task failure propagates across multiple generations even if
|
|||||||
an intermediate generation has already exited:
|
an intermediate generation has already exited:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
# use std::task;
|
||||||
# fn sleep_forever() { loop { task::yield() } }
|
# fn sleep_forever() { loop { task::yield() } }
|
||||||
# fn wait_for_a_while() { for 1000.times { task::yield() } }
|
# fn wait_for_a_while() { for 1000.times { task::yield() } }
|
||||||
# do task::try::<int> {
|
# do task::try::<int> {
|
||||||
@ -439,6 +565,7 @@ Finally, tasks can be configured to not propagate failure to each
|
|||||||
other at all, using `task::spawn_unlinked` for _isolated failure_.
|
other at all, using `task::spawn_unlinked` for _isolated failure_.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
# use std::task;
|
||||||
# fn random() -> uint { 100 }
|
# fn random() -> uint { 100 }
|
||||||
# fn sleep_for(i: uint) { for i.times { task::yield() } }
|
# fn sleep_for(i: uint) { for i.times { task::yield() } }
|
||||||
# do task::try::<()> {
|
# do task::try::<()> {
|
||||||
@ -457,7 +584,7 @@ fail!();
|
|||||||
|
|
||||||
A very common thing to do is to spawn a child task where the parent
|
A very common thing to do is to spawn a child task where the parent
|
||||||
and child both need to exchange messages with each other. The
|
and child both need to exchange messages with each other. The
|
||||||
function `std::comm::DuplexStream()` supports this pattern. We'll
|
function `extra::comm::DuplexStream()` supports this pattern. We'll
|
||||||
look briefly at how to use it.
|
look briefly at how to use it.
|
||||||
|
|
||||||
To see how `DuplexStream()` works, we will create a child task
|
To see how `DuplexStream()` works, we will create a child task
|
||||||
@ -466,7 +593,8 @@ the string in response. The child terminates when it receives `0`.
|
|||||||
Here is the function that implements the child task:
|
Here is the function that implements the child task:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use std::comm::DuplexStream;
|
# use extra::comm::DuplexStream;
|
||||||
|
# use std::uint;
|
||||||
fn stringifier(channel: &DuplexStream<~str, uint>) {
|
fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||||
let mut value: uint;
|
let mut value: uint;
|
||||||
loop {
|
loop {
|
||||||
@ -488,8 +616,9 @@ response itself is simply the stringified version of the received value,
|
|||||||
Here is the code for the parent task:
|
Here is the code for the parent task:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# use core::task::spawn;
|
# use std::task::spawn;
|
||||||
# use std::comm::DuplexStream;
|
# use std::uint;
|
||||||
|
# use extra::comm::DuplexStream;
|
||||||
# fn stringifier(channel: &DuplexStream<~str, uint>) {
|
# fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||||
# let mut value: uint;
|
# let mut value: uint;
|
||||||
# loop {
|
# loop {
|
||||||
@ -522,4 +651,3 @@ The parent task first calls `DuplexStream` to create a pair of bidirectional
|
|||||||
endpoints. It then uses `task::spawn` to create the child task, which captures
|
endpoints. It then uses `task::spawn` to create the child task, which captures
|
||||||
one end of the communication channel. As a result, both parent and child can
|
one end of the communication channel. As a result, both parent and child can
|
||||||
send and receive data to and from the other.
|
send and receive data to and from the other.
|
||||||
|
|
||||||
|
557
doc/tutorial.md
557
doc/tutorial.md
File diff suppressed because it is too large
Load Diff
@ -7,4 +7,3 @@
|
|||||||
</center>
|
</center>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
73
man/rustc.1
73
man/rustc.1
@ -1,4 +1,4 @@
|
|||||||
.TH RUSTC "1" "February 2013" "rustc 0.6" "User Commands"
|
.TH RUSTC "1" "July 2013" "rustc 0.7" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
rustc \- rust compiler
|
rustc \- rust compiler
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -33,6 +33,12 @@ Add a directory to the library search path
|
|||||||
\fB\-\-lib\fR
|
\fB\-\-lib\fR
|
||||||
Compile a library crate
|
Compile a library crate
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-linker\fR LINKER
|
||||||
|
Program to use for linking instead of the default
|
||||||
|
.TP
|
||||||
|
\fB\-\-link-args\fR FLAGS
|
||||||
|
A space-separated list of flags passed to the linker
|
||||||
|
.TP
|
||||||
\fB\-\-ls\fR
|
\fB\-\-ls\fR
|
||||||
List the symbols defined by a library crate
|
List the symbols defined by a library crate
|
||||||
.TP
|
.TP
|
||||||
@ -48,6 +54,11 @@ Write output to <filename>
|
|||||||
\fB\-\-opt\-level\fR LEVEL
|
\fB\-\-opt\-level\fR LEVEL
|
||||||
Optimize with possible levels 0-3
|
Optimize with possible levels 0-3
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-passes\fR NAMES
|
||||||
|
Comma- or space-separated list of optimization passes. Overrides
|
||||||
|
the default passes for the optimization level. A value of 'list'
|
||||||
|
will list the available passes.
|
||||||
|
.TP
|
||||||
\fB\-\-out\-dir\fR DIR
|
\fB\-\-out\-dir\fR DIR
|
||||||
Write output to compiler-chosen filename in <dir>
|
Write output to compiler-chosen filename in <dir>
|
||||||
.TP
|
.TP
|
||||||
@ -77,6 +88,12 @@ Target triple cpu-manufacturer-kernel[-os] to compile for (see
|
|||||||
http://sources.redhat.com/autobook/autobook/autobook_17.html
|
http://sources.redhat.com/autobook/autobook/autobook_17.html
|
||||||
for detail)
|
for detail)
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-target-feature\fR TRIPLE
|
||||||
|
Target-specific attributes (see llc -mattr=help for detail)
|
||||||
|
.TP
|
||||||
|
\fB\-\-android-cross-path\fR PATH
|
||||||
|
The path to the Android NDK
|
||||||
|
.TP
|
||||||
\fB\-W\fR help
|
\fB\-W\fR help
|
||||||
Print 'lint' options and default settings
|
Print 'lint' options and default settings
|
||||||
.TP
|
.TP
|
||||||
@ -94,56 +111,6 @@ Set lint forbidden
|
|||||||
.TP
|
.TP
|
||||||
\fB\-Z\fR FLAG
|
\fB\-Z\fR FLAG
|
||||||
Set internal debugging options. Use "-Z help" to print available options.
|
Set internal debugging options. Use "-Z help" to print available options.
|
||||||
|
|
||||||
Available debug flags are:
|
|
||||||
.RS
|
|
||||||
.IP \[bu]
|
|
||||||
\fBverbose\fR - in general, enable more debug printouts
|
|
||||||
.IP \[bu]
|
|
||||||
\fBtime\-passes\fR - measure time of each rustc pass
|
|
||||||
.IP \[bu]
|
|
||||||
\fBcount\-llvm\-insns\fR - count where LLVM instrs originate
|
|
||||||
.IP \[bu]
|
|
||||||
\fBtime\-llvm\-passes\fR - measure time of each LLVM pass
|
|
||||||
.IP \[bu]
|
|
||||||
\fBtrans\-stats\fR - gather trans statistics
|
|
||||||
.IP \[bu]
|
|
||||||
\fBno\-asm\-comments\fR - omit comments when using \fI\-S\fR
|
|
||||||
.IP \[bu]
|
|
||||||
\fBno\-verify\fR - skip LLVM verification
|
|
||||||
.IP \[bu]
|
|
||||||
\fBtrace\fR - emit trace logs
|
|
||||||
.IP \[bu]
|
|
||||||
\fBcoherence\fR - perform coherence checking
|
|
||||||
.IP \[bu]
|
|
||||||
\fBborrowck\-stats\fR - gather borrowck statistics
|
|
||||||
.IP \[bu]
|
|
||||||
\fBborrowck\-note\-pure\fR - note where purity is req'd
|
|
||||||
.IP \[bu]
|
|
||||||
\fBborrowck\-note\-loan\fR - note where loans are req'd
|
|
||||||
.IP \[bu]
|
|
||||||
\fBno\-landing\-pads\fR - omit landing pads for unwinding
|
|
||||||
.IP \[bu]
|
|
||||||
\fBdebug\-llvm\fR - enable debug output from LLVM
|
|
||||||
.IP \[bu]
|
|
||||||
\fBcount\-type\-sizes\fR - count the sizes of aggregate types
|
|
||||||
.IP \[bu]
|
|
||||||
\fBmeta\-stats\fR - gather metadata statistics
|
|
||||||
.IP \[bu]
|
|
||||||
\fBno\-opt\fR - do not optimize, even if \fI\-O\fR is passed
|
|
||||||
.IP \[bu]
|
|
||||||
\fBno\-monomorphic\-collapse\fR - do not collapse template instantiations
|
|
||||||
.IP \[bu]
|
|
||||||
\fBgc\fR - Garbage collect shared data (experimental)
|
|
||||||
.IP \[bu]
|
|
||||||
\fBjit\fR - Execute using JIT (experimental)
|
|
||||||
.IP \[bu]
|
|
||||||
\fBextra\-debug\-info\fR - Extra debugging info (experimental)
|
|
||||||
.IP \[bu]
|
|
||||||
\fBdebug\-info\fR - Produce debug info (experimental)
|
|
||||||
.IP \[bu]
|
|
||||||
\fBstatic\fR - Use or produce static libraries or binaries (experimental)
|
|
||||||
.RE
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-v\fR, \fB\-\-version\fR
|
\fB\-v\fR, \fB\-\-version\fR
|
||||||
Print version info and exit
|
Print version info and exit
|
||||||
@ -170,5 +137,5 @@ See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
|
|||||||
<\fIgraydon@mozilla.com\fR> is the project leader.
|
<\fIgraydon@mozilla.com\fR> is the project leader.
|
||||||
|
|
||||||
.SH "COPYRIGHT"
|
.SH "COPYRIGHT"
|
||||||
This work is licensed under MIT-like terms. See \fBLICENSE.txt\fR
|
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR
|
||||||
in the rust source distribution.
|
file in the rust source distribution.
|
||||||
|
20
mk/clean.mk
20
mk/clean.mk
@ -20,10 +20,10 @@ CLEAN_STAGE_RULES = \
|
|||||||
clean$(stage)_T_$(target)_H_$(host))))
|
clean$(stage)_T_$(target)_H_$(host))))
|
||||||
|
|
||||||
CLEAN_LLVM_RULES = \
|
CLEAN_LLVM_RULES = \
|
||||||
$(foreach target, $(CFG_TARGET_TRIPLES), \
|
$(foreach target, $(CFG_HOST_TRIPLES), \
|
||||||
clean-llvm$(target))
|
clean-llvm$(target))
|
||||||
|
|
||||||
.PHONY: clean clean-all clean-misc
|
.PHONY: clean clean-all clean-misc clean-llvm
|
||||||
|
|
||||||
clean-all: clean clean-llvm
|
clean-all: clean clean-llvm
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ clean-misc:
|
|||||||
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
|
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
|
||||||
$(Q)rm -Rf $(DOCS)
|
$(Q)rm -Rf $(DOCS)
|
||||||
$(Q)rm -Rf $(GENERATED)
|
$(Q)rm -Rf $(GENERATED)
|
||||||
$(Q)rm -f tmp/*.log tmp/*.rc tmp/*.rs tmp/*.ok
|
$(Q)rm -f tmp/*
|
||||||
$(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist
|
$(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist
|
||||||
$(Q)rm -Rf $(foreach ext, \
|
$(Q)rm -Rf $(foreach ext, \
|
||||||
html aux cp fn ky log pdf pg toc tp vr cps, \
|
html aux cp fn ky log pdf pg toc tp vr cps, \
|
||||||
@ -63,27 +63,24 @@ define CLEAN_HOST_STAGE_N
|
|||||||
|
|
||||||
clean$(1)_H_$(2):
|
clean$(1)_H_$(2):
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustc$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustc$(X_$(2))
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/fuzzer$(X_$(2))
|
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
|
||||||
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
|
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBFUZZER_$(2))
|
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_CORELIB_$(2))
|
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
|
||||||
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTI_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTI_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUST_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUST_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CORELIB_GLOB_$(2))
|
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
|
||||||
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_GLOB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBFUZZER_GLOB_$(2))
|
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
|
||||||
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB_$(2))
|
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB_$(2))
|
||||||
@ -101,27 +98,24 @@ define CLEAN_TARGET_STAGE_N
|
|||||||
|
|
||||||
clean$(1)_T_$(2)_H_$(3):
|
clean$(1)_T_$(2)_H_$(3):
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$(X_$(2))
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/fuzzer$(X_$(2))
|
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
|
||||||
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
|
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBFUZZER_$(2))
|
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2))
|
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
|
||||||
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUST_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUST_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CORELIB_GLOB_$(2))
|
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
|
||||||
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_GLOB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBFUZZER_GLOB_$(2))
|
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
|
||||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTI_GLOB_$(2))
|
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTI_GLOB_$(2))
|
||||||
|
@ -18,6 +18,7 @@ PKG_FILES := \
|
|||||||
$(S)COPYRIGHT \
|
$(S)COPYRIGHT \
|
||||||
$(S)LICENSE-APACHE \
|
$(S)LICENSE-APACHE \
|
||||||
$(S)LICENSE-MIT \
|
$(S)LICENSE-MIT \
|
||||||
|
$(S)AUTHORS.txt \
|
||||||
$(S)README.md \
|
$(S)README.md \
|
||||||
$(S)configure $(S)Makefile.in \
|
$(S)configure $(S)Makefile.in \
|
||||||
$(S)man \
|
$(S)man \
|
||||||
@ -31,10 +32,9 @@ PKG_FILES := \
|
|||||||
librustc \
|
librustc \
|
||||||
compiletest \
|
compiletest \
|
||||||
etc \
|
etc \
|
||||||
libfuzzer \
|
libextra \
|
||||||
libcore \
|
|
||||||
libsyntax \
|
|
||||||
libstd \
|
libstd \
|
||||||
|
libsyntax \
|
||||||
rt \
|
rt \
|
||||||
librustdoc \
|
librustdoc \
|
||||||
rustllvm \
|
rustllvm \
|
||||||
@ -57,7 +57,7 @@ LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT
|
|||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
$(PKG_EXE): rust.iss modpath.iss LICENSE.txt rust-logo.ico \
|
$(PKG_EXE): rust.iss modpath.iss LICENSE.txt rust-logo.ico \
|
||||||
$(PKG_FILES) all rustc-stage3
|
$(PKG_FILES) $(CSREQ3_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
|
||||||
@$(call E, ISCC: $@)
|
@$(call E, ISCC: $@)
|
||||||
$(Q)"$(CFG_ISCC)" $<
|
$(Q)"$(CFG_ISCC)" $<
|
||||||
endif
|
endif
|
||||||
|
102
mk/docs.mk
102
mk/docs.mk
@ -16,15 +16,8 @@ DOCS :=
|
|||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Pandoc (reference-manual related)
|
# Docs, from pandoc, rustdoc (which runs pandoc), and node
|
||||||
######################################################################
|
######################################################################
|
||||||
ifeq ($(CFG_PANDOC),)
|
|
||||||
$(info cfg: no pandoc found, omitting doc/rust.pdf)
|
|
||||||
else
|
|
||||||
|
|
||||||
ifeq ($(CFG_NODE),)
|
|
||||||
$(info cfg: no node found, omitting doc/tutorial.html)
|
|
||||||
else
|
|
||||||
|
|
||||||
doc/rust.css: rust.css
|
doc/rust.css: rust.css
|
||||||
@$(call E, cp: $@)
|
@$(call E, cp: $@)
|
||||||
@ -34,6 +27,18 @@ doc/manual.css: manual.css
|
|||||||
@$(call E, cp: $@)
|
@$(call E, cp: $@)
|
||||||
$(Q)cp -a $< $@ 2> /dev/null
|
$(Q)cp -a $< $@ 2> /dev/null
|
||||||
|
|
||||||
|
ifeq ($(CFG_PANDOC),)
|
||||||
|
$(info cfg: no pandoc found, omitting docs)
|
||||||
|
NO_DOCS = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CFG_NODE),)
|
||||||
|
$(info cfg: no node found, omitting docs)
|
||||||
|
NO_DOCS = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(NO_DOCS),1)
|
||||||
|
|
||||||
DOCS += doc/rust.html
|
DOCS += doc/rust.html
|
||||||
doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
|
doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
|
||||||
@$(call E, pandoc: $@)
|
@$(call E, pandoc: $@)
|
||||||
@ -47,19 +52,8 @@ doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
|
|||||||
--css=manual.css \
|
--css=manual.css \
|
||||||
--include-before-body=doc/version_info.html \
|
--include-before-body=doc/version_info.html \
|
||||||
--output=$@
|
--output=$@
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(CFG_PDFLATEX),)
|
DOCS += doc/rust.tex
|
||||||
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
|
|
||||||
else
|
|
||||||
ifeq ($(CFG_XETEX),)
|
|
||||||
$(info cfg: no xetex found, disabling doc/rust.pdf)
|
|
||||||
else
|
|
||||||
ifeq ($(CFG_LUATEX),)
|
|
||||||
$(info cfg: lacking luatex, disabling pdflatex)
|
|
||||||
else
|
|
||||||
|
|
||||||
DOCS += doc/rust.pdf
|
|
||||||
doc/rust.tex: rust.md doc/version.md
|
doc/rust.tex: rust.md doc/version.md
|
||||||
@$(call E, pandoc: $@)
|
@$(call E, pandoc: $@)
|
||||||
$(Q)$(CFG_NODE) $(S)doc/prep.js $< | \
|
$(Q)$(CFG_NODE) $(S)doc/prep.js $< | \
|
||||||
@ -70,23 +64,19 @@ doc/rust.tex: rust.md doc/version.md
|
|||||||
--from=markdown --to=latex \
|
--from=markdown --to=latex \
|
||||||
--output=$@
|
--output=$@
|
||||||
|
|
||||||
doc/rust.pdf: doc/rust.tex
|
DOCS += doc/rustpkg.html
|
||||||
@$(call E, pdflatex: $@)
|
doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css
|
||||||
$(Q)$(CFG_PDFLATEX) \
|
@$(call E, pandoc: $@)
|
||||||
-interaction=batchmode \
|
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||||
-output-directory=doc \
|
"$(CFG_PANDOC)" \
|
||||||
$<
|
--standalone --toc \
|
||||||
|
--section-divs \
|
||||||
endif
|
--number-sections \
|
||||||
endif
|
--from=markdown --to=html \
|
||||||
endif
|
--css=rust.css \
|
||||||
|
--css=manual.css \
|
||||||
######################################################################
|
--include-before-body=doc/version_info.html \
|
||||||
# Node (tutorial related)
|
--output=$@
|
||||||
######################################################################
|
|
||||||
ifeq ($(CFG_NODE),)
|
|
||||||
$(info cfg: no node found, omitting doc/tutorial.html)
|
|
||||||
else
|
|
||||||
|
|
||||||
DOCS += doc/tutorial.html
|
DOCS += doc/tutorial.html
|
||||||
doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css
|
doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css
|
||||||
@ -109,6 +99,16 @@ doc/tutorial-macros.html: tutorial-macros.md doc/version_info.html \
|
|||||||
--include-before-body=doc/version_info.html \
|
--include-before-body=doc/version_info.html \
|
||||||
--output=$@
|
--output=$@
|
||||||
|
|
||||||
|
DOCS += doc/tutorial-container.html
|
||||||
|
doc/tutorial-container.html: tutorial-container.md doc/version_info.html doc/rust.css
|
||||||
|
@$(call E, pandoc: $@)
|
||||||
|
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||||
|
$(CFG_PANDOC) --standalone --toc \
|
||||||
|
--section-divs --number-sections \
|
||||||
|
--from=markdown --to=html --css=rust.css \
|
||||||
|
--include-before-body=doc/version_info.html \
|
||||||
|
--output=$@
|
||||||
|
|
||||||
DOCS += doc/tutorial-ffi.html
|
DOCS += doc/tutorial-ffi.html
|
||||||
doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css
|
doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css
|
||||||
@$(call E, pandoc: $@)
|
@$(call E, pandoc: $@)
|
||||||
@ -139,9 +139,29 @@ doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css
|
|||||||
--include-before-body=doc/version_info.html \
|
--include-before-body=doc/version_info.html \
|
||||||
--output=$@
|
--output=$@
|
||||||
|
|
||||||
endif
|
ifeq ($(CFG_PDFLATEX),)
|
||||||
endif
|
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
|
||||||
|
else
|
||||||
|
ifeq ($(CFG_XETEX),)
|
||||||
|
$(info cfg: no xetex found, disabling doc/rust.pdf)
|
||||||
|
else
|
||||||
|
ifeq ($(CFG_LUATEX),)
|
||||||
|
$(info cfg: lacking luatex, disabling pdflatex)
|
||||||
|
else
|
||||||
|
|
||||||
|
DOCS += doc/rust.pdf
|
||||||
|
doc/rust.pdf: doc/rust.tex
|
||||||
|
@$(call E, pdflatex: $@)
|
||||||
|
$(Q)$(CFG_PDFLATEX) \
|
||||||
|
-interaction=batchmode \
|
||||||
|
-output-directory=doc \
|
||||||
|
$<
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif # No pandoc / node
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# LLnextgen (grammar analysis from refman)
|
# LLnextgen (grammar analysis from refman)
|
||||||
@ -163,7 +183,7 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Rustdoc (libcore/std)
|
# Rustdoc (libstd/extra)
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
ifeq ($(CFG_PANDOC),)
|
ifeq ($(CFG_PANDOC),)
|
||||||
@ -189,8 +209,8 @@ doc/$(1)/rust.css: rust.css
|
|||||||
DOCS += doc/$(1)/index.html
|
DOCS += doc/$(1)/index.html
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call libdoc,core,$(CORELIB_CRATE),$(CORELIB_INPUTS)))
|
|
||||||
$(eval $(call libdoc,std,$(STDLIB_CRATE),$(STDLIB_INPUTS)))
|
$(eval $(call libdoc,std,$(STDLIB_CRATE),$(STDLIB_INPUTS)))
|
||||||
|
$(eval $(call libdoc,extra,$(EXTRALIB_CRATE),$(EXTRALIB_INPUTS)))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
86
mk/host.mk
86
mk/host.mk
@ -28,8 +28,10 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
|
|||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
|
||||||
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
|
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
|
||||||
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
|
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
|
||||||
|
| $$(HBIN$(2)_H_$(4))/
|
||||||
|
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
@ -38,8 +40,10 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
|
|||||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
||||||
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
|
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
|
||||||
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
|
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
|
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \
|
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \
|
||||||
@ -50,8 +54,9 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
|
|||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBSYNTAX_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBSYNTAX_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
|
||||||
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
|
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
|
||||||
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
|
$$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \
|
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \
|
||||||
@ -59,62 +64,77 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
|
|||||||
$$(HLIB$(2)_H_$(4))
|
$$(HLIB$(2)_H_$(4))
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4))
|
|
||||||
@$$(call E, cp: $$@)
|
|
||||||
$$(Q)cp $$< $$@
|
|
||||||
# Subtle: We do not let the shell expand $(CORELIB_DSYM_GLOB) directly rather
|
|
||||||
# we use Make's $$(wildcard) facility. The reason is that, on mac, when using
|
|
||||||
# USE_SNAPSHOT_CORELIB, we copy the core.dylib file out of the snapshot.
|
|
||||||
# In that case, there is no .dSYM file. Annoyingly, bash then refuses to expand
|
|
||||||
# glob, and cp reports an error because libcore-*.dylib.dsym does not exist.
|
|
||||||
# Make instead expands the glob to nothing, which gives us the correct behavior.
|
|
||||||
# (Copy .dsym file if it exists, but do nothing otherwise)
|
|
||||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(CORELIB_GLOB_$(4)) \
|
|
||||||
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(CORELIB_DSYM_GLOB_$(4))) \
|
|
||||||
$$(HLIB$(2)_H_$(4))
|
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
|
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)) \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4))
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
# Subtle: We do not let the shell expand $(STDLIB_DSYM_GLOB) directly rather
|
||||||
|
# we use Make's $$(wildcard) facility. The reason is that, on mac, when using
|
||||||
|
# USE_SNAPSHOT_STDLIB, we copy the std.dylib file out of the snapshot.
|
||||||
|
# In that case, there is no .dSYM file. Annoyingly, bash then refuses to expand
|
||||||
|
# glob, and cp reports an error because libstd-*.dylib.dsym does not exist.
|
||||||
|
# Make instead expands the glob to nothing, which gives us the correct behavior.
|
||||||
|
# (Copy .dsym file if it exists, but do nothing otherwise)
|
||||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \
|
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \
|
||||||
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
|
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
|
||||||
$$(HLIB$(2)_H_$(4))
|
$$(HLIB$(2)_H_$(4))
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/libcore.rlib: \
|
$$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
|
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
|
||||||
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_GLOB_$(4)) \
|
||||||
|
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_DSYM_GLOB_$(4))) \
|
||||||
|
$$(HLIB$(2)_H_$(4))
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/libstd.rlib: \
|
$$(HLIB$(2)_H_$(4))/libstd.rlib: \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \
|
||||||
$$(HLIB$(2)_H_$(4))/libcore.rlib \
|
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
|
||||||
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
|
@$$(call E, cp: $$@)
|
||||||
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
|
$$(HLIB$(2)_H_$(4))/libextra.rlib: \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/libextra.rlib \
|
||||||
|
$$(HLIB$(2)_H_$(4))/libstd.rlib \
|
||||||
|
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/librustc.rlib: \
|
$$(HLIB$(2)_H_$(4))/librustc.rlib: \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \
|
||||||
$$(HLIB$(2)_H_$(4))/libcore.rlib \
|
|
||||||
$$(HLIB$(2)_H_$(4))/libstd.rlib \
|
$$(HLIB$(2)_H_$(4))/libstd.rlib \
|
||||||
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
|
$$(HLIB$(2)_H_$(4))/libextra.rlib \
|
||||||
|
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \
|
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \
|
||||||
|
| $$(HLIB$(2)_H_$(4))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
|
$$(HBIN$(2)_H_$(4))/:
|
||||||
|
mkdir -p $$@
|
||||||
|
|
||||||
|
ifneq ($(CFG_LIBDIR),bin)
|
||||||
|
$$(HLIB$(2)_H_$(4))/:
|
||||||
|
mkdir -p $$@
|
||||||
|
endif
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(foreach t,$(CFG_HOST_TRIPLES), \
|
$(foreach t,$(CFG_HOST_TRIPLES), \
|
||||||
|
@ -52,10 +52,10 @@ define INSTALL_TARGET_N
|
|||||||
install-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
install-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
||||||
$$(Q)mkdir -p $$(PTL$(1)$(2))
|
$$(Q)mkdir -p $$(PTL$(1)$(2))
|
||||||
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CFG_RUNTIME_$(1)))
|
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CFG_RUNTIME_$(1)))
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
|
||||||
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CORELIB_GLOB_$(1)))
|
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(STDLIB_GLOB_$(1)))
|
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(STDLIB_GLOB_$(1)))
|
||||||
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
|
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(EXTRALIB_GLOB_$(1)))
|
||||||
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),libmorestack.a)
|
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),libmorestack.a)
|
||||||
|
|
||||||
endef
|
endef
|
||||||
@ -64,10 +64,10 @@ define INSTALL_HOST_N
|
|||||||
install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
||||||
$$(Q)mkdir -p $$(PTL$(1)$(2))
|
$$(Q)mkdir -p $$(PTL$(1)$(2))
|
||||||
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CFG_RUNTIME_$(1)))
|
$$(Q)$$(call INSTALL_LIB,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CFG_RUNTIME_$(1)))
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
|
||||||
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(CORELIB_GLOB_$(1)))
|
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(STDLIB_GLOB_$(1)))
|
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(STDLIB_GLOB_$(1)))
|
||||||
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
|
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(EXTRALIB_GLOB_$(1)))
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTC_GLOB_$(1)))
|
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTC_GLOB_$(1)))
|
||||||
$$(Q)$$(call INSTALL_LIB, \
|
$$(Q)$$(call INSTALL_LIB, \
|
||||||
@ -113,12 +113,14 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
|
|||||||
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(CORELIB_GLOB_$(CFG_BUILD_TRIPLE)))
|
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(EXTRALIB_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
|
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
|
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
|
||||||
$(Q)$(call INSTALL,$(S)/man, \
|
$(Q)$(call INSTALL,$(S)/man, \
|
||||||
@ -139,8 +141,8 @@ uninstall:
|
|||||||
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
|
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
|
||||||
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
|
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
|
||||||
$(Q)for i in \
|
$(Q)for i in \
|
||||||
$(call HOST_LIB_FROM_HL_GLOB,$(CORELIB_GLOB_$(CFG_BUILD_TRIPLE))) \
|
|
||||||
$(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE))) \
|
$(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE))) \
|
||||||
|
$(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_GLOB_$(CFG_BUILD_TRIPLE))) \
|
||||||
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE))) \
|
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE))) \
|
||||||
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
|
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
|
||||||
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
|
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
|
||||||
@ -152,3 +154,76 @@ uninstall:
|
|||||||
done
|
done
|
||||||
$(Q)rm -Rf $(PHL)/rustc
|
$(Q)rm -Rf $(PHL)/rustc
|
||||||
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1
|
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1
|
||||||
|
|
||||||
|
# target platform specific variables
|
||||||
|
# for arm-linux-androidabi
|
||||||
|
define DEF_ADB_DEVICE_STATUS
|
||||||
|
CFG_ADB_DEVICE_STATUS=$(1)
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
|
$(if $(findstring $(target),"arm-linux-androideabi"), \
|
||||||
|
$(if $(findstring adb,$(CFG_ADB)), \
|
||||||
|
$(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \
|
||||||
|
$(info install: install-runtime-target for $(target) enabled \
|
||||||
|
$(info install: android device attached) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, true))), \
|
||||||
|
$(info install: install-runtime-target for $(target) disabled \
|
||||||
|
$(info install: android device not attached) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, false))) \
|
||||||
|
), \
|
||||||
|
$(info install: install-runtime-target for $(target) disabled \
|
||||||
|
$(info install: adb not found) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, false))) \
|
||||||
|
), \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
ifeq (install-runtime-target,$(firstword $(MAKECMDGOALS)))
|
||||||
|
$(eval $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)):;@:)
|
||||||
|
L_TOKEN := $(word 2,$(MAKECMDGOALS))
|
||||||
|
ifeq ($(L_TOKEN),)
|
||||||
|
CFG_RUNTIME_PUSH_DIR=/system/lib
|
||||||
|
else
|
||||||
|
CFG_RUNTIME_PUSH_DIR=$(L_TOKEN)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CFG_ADB_DEVICE_STATUS),true)
|
||||||
|
ifdef VERBOSE
|
||||||
|
ADB = adb $(1)
|
||||||
|
ADB_PUSH = adb push $(1) $(2)
|
||||||
|
ADB_SHELL = adb shell $(1) $(2)
|
||||||
|
else
|
||||||
|
ADB = $(Q)$(call E, adb $(1)) && adb $(1) 1>/dev/null
|
||||||
|
ADB_PUSH = $(Q)$(call E, adb push $(1)) && adb push $(1) $(2) 1>/dev/null
|
||||||
|
ADB_SHELL = $(Q)$(call E, adb shell $(1) $(2)) && adb shell $(1) $(2) 1>/dev/null
|
||||||
|
endif
|
||||||
|
|
||||||
|
define INSTALL_RUNTIME_TARGET_N
|
||||||
|
install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
|
||||||
|
$(Q)$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR))
|
||||||
|
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),$(CFG_RUNTIME_PUSH_DIR))
|
||||||
|
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
|
||||||
|
$(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(EXTRALIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
|
||||||
|
endef
|
||||||
|
|
||||||
|
define INSTALL_RUNTIME_TARGET_CLEANUP_N
|
||||||
|
install-runtime-target-$(1)-cleanup:
|
||||||
|
$(Q)$(call ADB,remount)
|
||||||
|
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CFG_RUNTIME_$(1)))
|
||||||
|
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1)))
|
||||||
|
$(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(EXTRALIB_GLOB_$(1)))
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD_TRIPLE)))
|
||||||
|
$(eval $(call INSTALL_RUNTIME_TARGET_CLEANUP_N,arm-linux-androideabi))
|
||||||
|
|
||||||
|
install-runtime-target: \
|
||||||
|
install-runtime-target-arm-linux-androideabi-cleanup \
|
||||||
|
install-runtime-target-arm-linux-androideabi-host-$(CFG_BUILD_TRIPLE)
|
||||||
|
else
|
||||||
|
install-runtime-target:
|
||||||
|
@echo "No device to install runtime library"
|
||||||
|
@echo
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
105
mk/platform.mk
105
mk/platform.mk
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
# Create variables HOST_<triple> containing the host part
|
# Create variables HOST_<triple> containing the host part
|
||||||
# of each target triple. For example, the triple i686-darwin-macos
|
# of each target triple. For example, the triple i686-darwin-macos
|
||||||
# would create a variable HOST_i686-darwin-macos with the value
|
# would create a variable HOST_i686-darwin-macos with the value
|
||||||
# i386.
|
# i386.
|
||||||
define DEF_HOST_VAR
|
define DEF_HOST_VAR
|
||||||
HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1))))
|
HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1))))
|
||||||
@ -29,7 +29,7 @@ $(foreach t,$(CFG_TARGET_TRIPLES),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
|
|||||||
# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
|
# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
|
||||||
# has a frame pointer and the stack walker can understand it. Turning off
|
# has a frame pointer and the stack walker can understand it. Turning off
|
||||||
# frame pointers everywhere is overkill
|
# frame pointers everywhere is overkill
|
||||||
CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer
|
CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer -DUSE_UTF8
|
||||||
|
|
||||||
# On Darwin, we need to run dsymutil so the debugging information ends
|
# On Darwin, we need to run dsymutil so the debugging information ends
|
||||||
# up in the right place. On other platforms, it automatically gets
|
# up in the right place. On other platforms, it automatically gets
|
||||||
@ -105,10 +105,35 @@ ifeq ($(CFG_C_COMPILER),gcc)
|
|||||||
ifeq ($(origin CPP),default)
|
ifeq ($(origin CPP),default)
|
||||||
CPP=gcc
|
CPP=gcc
|
||||||
endif
|
endif
|
||||||
|
else
|
||||||
|
ifeq ($(CFG_C_COMPILER),ccache clang)
|
||||||
|
# The -Qunused-arguments sidesteps spurious warnings from clang
|
||||||
|
ifeq ($(origin CC),default)
|
||||||
|
CC=ccache clang -Qunused-arguments
|
||||||
|
endif
|
||||||
|
ifeq ($(origin CXX),default)
|
||||||
|
CXX=ccache clang++ -Qunused-arguments
|
||||||
|
endif
|
||||||
|
ifeq ($(origin CPP),default)
|
||||||
|
CPP=ccache clang -Qunused-arguments
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
ifeq ($(CFG_C_COMPILER),ccache gcc)
|
||||||
|
ifeq ($(origin CC),default)
|
||||||
|
CC=ccache gcc
|
||||||
|
endif
|
||||||
|
ifeq ($(origin CXX),default)
|
||||||
|
CXX=ccache g++
|
||||||
|
endif
|
||||||
|
ifeq ($(origin CPP),default)
|
||||||
|
CPP=ccache gcc
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
CFG_ERR := $(error please try on a system with gcc or clang)
|
CFG_ERR := $(error please try on a system with gcc or clang)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# x86_64-unknown-linux-gnu configuration
|
# x86_64-unknown-linux-gnu configuration
|
||||||
@ -121,7 +146,7 @@ CFG_LIB_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.so
|
|||||||
CFG_LIB_DSYM_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
CFG_LIB_DSYM_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
||||||
CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64
|
CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64
|
||||||
CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti
|
CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti
|
||||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -lpthread -lrt -g -m64
|
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64
|
||||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-whole-archive
|
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-whole-archive
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
|
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||||
@ -147,7 +172,7 @@ CFG_LIB_GLOB_i686-unknown-linux-gnu=lib$(1)-*.so
|
|||||||
CFG_LIB_DSYM_GLOB_i686-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
CFG_LIB_DSYM_GLOB_i686-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
||||||
CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32
|
CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32
|
||||||
CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti
|
CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti
|
||||||
CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -lpthread -lrt -g -m32
|
CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32
|
||||||
CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-whole-archive
|
CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-whole-archive
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
|
CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||||
@ -173,7 +198,7 @@ CFG_LIB_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib
|
|||||||
CFG_LIB_DSYM_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib.dSYM
|
CFG_LIB_DSYM_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib.dSYM
|
||||||
CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_64
|
CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_64
|
||||||
CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti
|
CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti
|
||||||
CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -lpthread -framework CoreServices -Wl,-no_compact_unwind -m64
|
CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -pthread -framework CoreServices -Wl,-no_compact_unwind -m64
|
||||||
CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list,
|
CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list,
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-darwin :=
|
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-darwin :=
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-darwin :=
|
CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-darwin :=
|
||||||
@ -198,7 +223,7 @@ CFG_LIB_GLOB_i686-apple-darwin=lib$(1)-*.dylib
|
|||||||
CFG_LIB_DSYM_GLOB_i686-apple-darwin=lib$(1)-*.dylib.dSYM
|
CFG_LIB_DSYM_GLOB_i686-apple-darwin=lib$(1)-*.dylib.dSYM
|
||||||
CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386
|
CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386
|
||||||
CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti
|
CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti
|
||||||
CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -lpthread -framework CoreServices -Wl,-no_compact_unwind -m32
|
CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -pthread -framework CoreServices -Wl,-no_compact_unwind -m32
|
||||||
CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list,
|
CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list,
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-apple-darwin :=
|
CFG_GCCISH_PRE_LIB_FLAGS_i686-apple-darwin :=
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_i686-apple-darwin :=
|
CFG_GCCISH_POST_LIB_FLAGS_i686-apple-darwin :=
|
||||||
@ -239,6 +264,57 @@ CFG_RUN_arm-linux-androideabi=
|
|||||||
CFG_RUN_TARG_arm-linux-androideabi=
|
CFG_RUN_TARG_arm-linux-androideabi=
|
||||||
RUSTC_FLAGS_arm-linux-androideabi :=--android-cross-path=$(CFG_ANDROID_CROSS_PATH)
|
RUSTC_FLAGS_arm-linux-androideabi :=--android-cross-path=$(CFG_ANDROID_CROSS_PATH)
|
||||||
|
|
||||||
|
# arm-unknown-linux-gnueabihf configuration
|
||||||
|
CC_arm-unknown-linux-gnueabihf=arm-linux-gnueabihf-gcc
|
||||||
|
CXX_arm-unknown-linux-gnueabihf=arm-linux-gnueabihf-g++
|
||||||
|
CPP_arm-unknown-linux-gnueabihf=arm-linux-gnueabihf-gcc -E
|
||||||
|
AR_arm-unknown-linux-gnueabihf=arm-linux-gnueabihf-ar
|
||||||
|
CFG_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).so
|
||||||
|
CFG_LIB_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.so
|
||||||
|
CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM
|
||||||
|
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC
|
||||||
|
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti
|
||||||
|
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
|
||||||
|
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
|
||||||
|
CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-whole-archive
|
||||||
|
CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-no-whole-archive
|
||||||
|
CFG_DEF_SUFFIX_arm-unknown-linux-gnueabihf := .linux.def
|
||||||
|
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabihf =
|
||||||
|
CFG_LIBUV_LINK_FLAGS_arm-unknown-linux-gnueabihf =
|
||||||
|
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabihf :=
|
||||||
|
CFG_WINDOWSY_arm-unknown-linux-gnueabihf :=
|
||||||
|
CFG_UNIXY_arm-unknown-linux-gnueabihf := 1
|
||||||
|
CFG_PATH_MUNGE_arm-unknown-linux-gnueabihf := true
|
||||||
|
CFG_LDPATH_arm-unknown-linux-gnueabihf :=
|
||||||
|
CFG_RUN_arm-unknown-linux-gnueabihf=
|
||||||
|
CFG_RUN_TARG_arm-unknown-linux-gnueabihf=
|
||||||
|
RUSTC_FLAGS_arm-unknown-linux-gnueabihf := --linker=$(CC_arm-unknown-linux-gnueabihf)
|
||||||
|
|
||||||
|
# mips-unknown-linux-gnu configuration
|
||||||
|
CC_mips-unknown-linux-gnu=mips-linux-gnu-gcc
|
||||||
|
CXX_mips-unknown-linux-gnu=mips-linux-gnu-g++
|
||||||
|
CPP_mips-unknown-linux-gnu=mips-linux-gnu-gcc -E
|
||||||
|
AR_mips-unknown-linux-gnu=mips-linux-gnu-ar
|
||||||
|
CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so
|
||||||
|
CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so
|
||||||
|
CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
||||||
|
CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh
|
||||||
|
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti
|
||||||
|
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
|
||||||
|
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||||
|
CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive
|
||||||
|
CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||||
|
CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def
|
||||||
|
CFG_INSTALL_NAME_mips-unknown-linux-gnu =
|
||||||
|
CFG_LIBUV_LINK_FLAGS_mips-unknown-linux-gnu =
|
||||||
|
CFG_EXE_SUFFIX_mips-unknown-linux-gnu :=
|
||||||
|
CFG_WINDOWSY_mips-unknown-linux-gnu :=
|
||||||
|
CFG_UNIXY_mips-unknown-linux-gnu := 1
|
||||||
|
CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
|
||||||
|
CFG_LDPATH_mips-unknown-linux-gnu :=
|
||||||
|
CFG_RUN_mips-unknown-linux-gnu=
|
||||||
|
CFG_RUN_TARG_mips-unknown-linux-gnu=
|
||||||
|
|
||||||
# i686-pc-mingw32 configuration
|
# i686-pc-mingw32 configuration
|
||||||
CC_i686-pc-mingw32=$(CC)
|
CC_i686-pc-mingw32=$(CC)
|
||||||
CXX_i686-pc-mingw32=$(CXX)
|
CXX_i686-pc-mingw32=$(CXX)
|
||||||
@ -251,8 +327,8 @@ CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -march=i686
|
|||||||
CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
|
CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
|
||||||
CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g
|
CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g
|
||||||
CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
|
CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
|
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
|
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
|
||||||
CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
|
CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
|
||||||
CFG_INSTALL_NAME_i686-pc-mingw32 =
|
CFG_INSTALL_NAME_i686-pc-mingw32 =
|
||||||
CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi
|
CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi
|
||||||
@ -300,13 +376,13 @@ CFG_LIB_NAME_x86_64-unknown-freebsd=lib$(1).so
|
|||||||
CFG_LIB_GLOB_x86_64-unknown-freebsd=lib$(1)-*.so
|
CFG_LIB_GLOB_x86_64-unknown-freebsd=lib$(1)-*.so
|
||||||
CFG_LIB_DSYM_GLOB_x86_64-unknown-freebsd=$(1)-*.dylib.dSYM
|
CFG_LIB_DSYM_GLOB_x86_64-unknown-freebsd=$(1)-*.dylib.dSYM
|
||||||
CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include
|
CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include
|
||||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -lpthread -lrt
|
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -pthread -lrt
|
||||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
|
CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
|
||||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-whole-archive
|
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-whole-archive
|
||||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-no-whole-archive
|
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-no-whole-archive
|
||||||
CFG_DEF_SUFFIX_x86_64-unknown-freebsd := .bsd.def
|
CFG_DEF_SUFFIX_x86_64-unknown-freebsd := .bsd.def
|
||||||
CFG_INSTALL_NAME_x86_64-unknown-freebsd =
|
CFG_INSTALL_NAME_x86_64-unknown-freebsd =
|
||||||
CFG_LIBUV_LINK_FLAGS_x86_64-unknown-freebsd := -lpthread -lkvm
|
CFG_LIBUV_LINK_FLAGS_x86_64-unknown-freebsd := -pthread -lkvm
|
||||||
CFG_EXE_SUFFIX_x86_64-unknown-freebsd :=
|
CFG_EXE_SUFFIX_x86_64-unknown-freebsd :=
|
||||||
CFG_WINDOWSY_x86_64-unknown-freebsd :=
|
CFG_WINDOWSY_x86_64-unknown-freebsd :=
|
||||||
CFG_UNIXY_x86_64-unknown-freebsd := 1
|
CFG_UNIXY_x86_64-unknown-freebsd := 1
|
||||||
@ -315,6 +391,15 @@ CFG_LDPATH_x86_64-unknown-freebsd :=
|
|||||||
CFG_RUN_x86_64-unknown-freebsd=$(2)
|
CFG_RUN_x86_64-unknown-freebsd=$(2)
|
||||||
CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
|
CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
|
||||||
|
|
||||||
|
ifeq ($(CFG_CCACHE_CPP2),1)
|
||||||
|
CCACHE_CPP2=1
|
||||||
|
export CCACHE_CPP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CFG_CCACHE_BASEDIR
|
||||||
|
CCACHE_BASEDIR=$(CFG_CCACHE_BASEDIR)
|
||||||
|
export CCACHE_BASEDIR
|
||||||
|
endif
|
||||||
|
|
||||||
define CFG_MAKE_TOOLCHAIN
|
define CFG_MAKE_TOOLCHAIN
|
||||||
CFG_COMPILE_C_$(1) = $$(CC_$(1)) \
|
CFG_COMPILE_C_$(1) = $$(CC_$(1)) \
|
||||||
|
5
mk/pp.mk
5
mk/pp.mk
@ -12,12 +12,11 @@
|
|||||||
ifdef PPFILES
|
ifdef PPFILES
|
||||||
PP_INPUTS_FILTERED := $(wildcard $(PPFILES))
|
PP_INPUTS_FILTERED := $(wildcard $(PPFILES))
|
||||||
else
|
else
|
||||||
PP_INPUTS = $(wildcard $(addprefix $(S)src/libcore/,*.rs */*.rs)) \
|
PP_INPUTS = $(wildcard $(addprefix $(S)src/libstd/,*.rs */*.rs)) \
|
||||||
$(wildcard $(addprefix $(S)src/libstd/,*.rs */*.rs)) \
|
$(wildcard $(addprefix $(S)src/libextra/,*.rs */*.rs)) \
|
||||||
$(wildcard $(addprefix $(S)src/rustc/,*.rs */*.rs */*/*.rs)) \
|
$(wildcard $(addprefix $(S)src/rustc/,*.rs */*.rs */*/*.rs)) \
|
||||||
$(wildcard $(S)src/test/*/*.rs \
|
$(wildcard $(S)src/test/*/*.rs \
|
||||||
$(S)src/test/*/*/*.rs) \
|
$(S)src/test/*/*/*.rs) \
|
||||||
$(wildcard $(S)src/fuzzer/*.rs) \
|
|
||||||
$(wildcard $(S)src/rustpkg/*.rs) \
|
$(wildcard $(S)src/rustpkg/*.rs) \
|
||||||
$(wildcard $(S)src/rusti/*.rs) \
|
$(wildcard $(S)src/rusti/*.rs) \
|
||||||
$(wildcard $(S)src/rust/*.rs)
|
$(wildcard $(S)src/rust/*.rs)
|
||||||
|
165
mk/rt.mk
165
mk/rt.mk
@ -1,32 +1,37 @@
|
|||||||
# This is a procedure to define the targets for building
|
# This is a procedure to define the targets for building
|
||||||
# the runtime.
|
# the runtime.
|
||||||
#
|
#
|
||||||
# Argument 1 is the target triple.
|
# Argument 1 is the target triple.
|
||||||
#
|
#
|
||||||
# This is not really the right place to explain this, but
|
# This is not really the right place to explain this, but
|
||||||
# for those of you who are not Makefile gurus, let me briefly
|
# for those of you who are not Makefile gurus, let me briefly
|
||||||
# cover the $ expansion system in use here, because it
|
# cover the $ expansion system in use here, because it
|
||||||
# confused me for a while! The variable DEF_RUNTIME_TARGETS
|
# confused me for a while! The variable DEF_RUNTIME_TARGETS
|
||||||
# will be defined once and then expanded with different
|
# will be defined once and then expanded with different
|
||||||
# values substituted for $(1) each time it is called.
|
# values substituted for $(1) each time it is called.
|
||||||
# That resulting text is then eval'd.
|
# That resulting text is then eval'd.
|
||||||
#
|
#
|
||||||
# For most variables, you could use a single $ sign. The result
|
# For most variables, you could use a single $ sign. The result
|
||||||
# is that the substitution would occur when the CALL occurs,
|
# is that the substitution would occur when the CALL occurs,
|
||||||
# I believe. The problem is that the automatic variables $< and $@
|
# I believe. The problem is that the automatic variables $< and $@
|
||||||
# need to be expanded-per-rule. Therefore, for those variables at
|
# need to be expanded-per-rule. Therefore, for those variables at
|
||||||
# least, you need $$< and $$@ in the variable text. This way, after
|
# least, you need $$< and $$@ in the variable text. This way, after
|
||||||
# the CALL substitution occurs, you will have $< and $@. This text
|
# the CALL substitution occurs, you will have $< and $@. This text
|
||||||
# will then be evaluated, and all will work as you like.
|
# will then be evaluated, and all will work as you like.
|
||||||
#
|
#
|
||||||
# Reader beware, this explanantion could be wrong, but it seems to
|
# Reader beware, this explanantion could be wrong, but it seems to
|
||||||
# fit the experimental data (i.e., I was able to get the system
|
# fit the experimental data (i.e., I was able to get the system
|
||||||
# working under these assumptions).
|
# working under these assumptions).
|
||||||
|
|
||||||
# Hack for passing flags into LIBUV, see below.
|
# Hack for passing flags into LIBUV, see below.
|
||||||
LIBUV_FLAGS_i386 = -m32 -fPIC
|
LIBUV_FLAGS_i386 = -m32 -fPIC
|
||||||
LIBUV_FLAGS_x86_64 = -m64 -fPIC
|
LIBUV_FLAGS_x86_64 = -m64 -fPIC
|
||||||
|
ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
||||||
LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99
|
LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99
|
||||||
|
else
|
||||||
|
LIBUV_FLAGS_arm = -fPIC -std=gnu99
|
||||||
|
endif
|
||||||
|
LIBUV_FLAGS_mips = -fPIC -mips32r2 -msoft-float -mabi=32
|
||||||
|
|
||||||
# when we're doing a snapshot build, we intentionally degrade as many
|
# when we're doing a snapshot build, we intentionally degrade as many
|
||||||
# features in libuv and the runtime as possible, to ease portability.
|
# features in libuv and the runtime as possible, to ease portability.
|
||||||
@ -36,14 +41,28 @@ ifneq ($(strip $(findstring snap,$(MAKECMDGOALS))),)
|
|||||||
SNAP_DEFINES=-DRUST_SNAPSHOT
|
SNAP_DEFINES=-DRUST_SNAPSHOT
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
define DEF_RUNTIME_TARGETS
|
define DEF_RUNTIME_TARGETS
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Runtime (C++) library variables
|
# Runtime (C++) library variables
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
RUNTIME_CXXS_$(1) := \
|
# $(1) is the target triple
|
||||||
|
# $(2) is the stage number
|
||||||
|
|
||||||
|
RUNTIME_CFLAGS_$(1)_$(2) = -D_RUST_STAGE$(2)
|
||||||
|
RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE$(2)
|
||||||
|
|
||||||
|
# XXX: Like with --cfg stage0, pass the defines for stage1 to the stage0
|
||||||
|
# build of non-build-triple host compilers
|
||||||
|
ifeq ($(2),0)
|
||||||
|
ifneq ($(strip $(CFG_BUILD_TRIPLE)),$(strip $(1)))
|
||||||
|
RUNTIME_CFLAGS_$(1)_$(2) = -D_RUST_STAGE1
|
||||||
|
RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
RUNTIME_CXXS_$(1)_$(2) := \
|
||||||
rt/sync/timer.cpp \
|
rt/sync/timer.cpp \
|
||||||
rt/sync/lock_and_signal.cpp \
|
rt/sync/lock_and_signal.cpp \
|
||||||
rt/sync/rust_thread.cpp \
|
rt/sync/rust_thread.cpp \
|
||||||
@ -75,72 +94,75 @@ RUNTIME_CXXS_$(1) := \
|
|||||||
rt/boxed_region.cpp \
|
rt/boxed_region.cpp \
|
||||||
rt/arch/$$(HOST_$(1))/context.cpp \
|
rt/arch/$$(HOST_$(1))/context.cpp \
|
||||||
rt/arch/$$(HOST_$(1))/gpr.cpp \
|
rt/arch/$$(HOST_$(1))/gpr.cpp \
|
||||||
rt/rust_android_dummy.cpp
|
rt/rust_android_dummy.cpp \
|
||||||
|
rt/rust_test_helpers.cpp
|
||||||
|
|
||||||
RUNTIME_CS_$(1) := rt/linenoise/linenoise.c rt/linenoise/utf8.c
|
RUNTIME_CS_$(1)_$(2) := rt/linenoise/linenoise.c rt/linenoise/utf8.c
|
||||||
|
|
||||||
RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \
|
RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
|
||||||
rt/arch/$$(HOST_$(1))/ccall.S \
|
rt/arch/$$(HOST_$(1))/ccall.S \
|
||||||
rt/arch/$$(HOST_$(1))/record_sp.S
|
rt/arch/$$(HOST_$(1))/record_sp.S
|
||||||
|
|
||||||
ifeq ($$(CFG_WINDOWSY_$(1)), 1)
|
ifeq ($$(CFG_WINDOWSY_$(1)), 1)
|
||||||
LIBUV_OSTYPE_$(1) := win
|
LIBUV_OSTYPE_$(1)_$(2) := win
|
||||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
|
LIBUV_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/libuv/libuv.a
|
||||||
|
JEMALLOC_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/jemalloc/lib/jemalloc.lib
|
||||||
else ifeq ($(OSTYPE_$(1)), apple-darwin)
|
else ifeq ($(OSTYPE_$(1)), apple-darwin)
|
||||||
LIBUV_OSTYPE_$(1) := mac
|
LIBUV_OSTYPE_$(1)_$(2) := mac
|
||||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
|
LIBUV_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/libuv/libuv.a
|
||||||
|
JEMALLOC_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/jemalloc/lib/libjemalloc_pic.a
|
||||||
else ifeq ($(OSTYPE_$(1)), unknown-freebsd)
|
else ifeq ($(OSTYPE_$(1)), unknown-freebsd)
|
||||||
LIBUV_OSTYPE_$(1) := unix/freebsd
|
LIBUV_OSTYPE_$(1)_$(2) := unix/freebsd
|
||||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
|
LIBUV_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/libuv/libuv.a
|
||||||
|
JEMALLOC_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/jemalloc/lib/libjemalloc_pic.a
|
||||||
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
||||||
LIBUV_OSTYPE_$(1) := unix/android
|
LIBUV_OSTYPE_$(1)_$(2) := unix/android
|
||||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
|
LIBUV_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/libuv/libuv.a
|
||||||
|
JEMALLOC_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/jemalloc/lib/libjemalloc_pic.a
|
||||||
else
|
else
|
||||||
LIBUV_OSTYPE_$(1) := unix/linux
|
LIBUV_OSTYPE_$(1)_$(2) := unix/linux
|
||||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
|
LIBUV_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/libuv/libuv.a
|
||||||
|
JEMALLOC_LIB_$(1)_$(2) := rt/$(1)/stage$(2)/jemalloc/lib/libjemalloc_pic.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
RUNTIME_DEF_$(1) := rt/rustrt$(CFG_DEF_SUFFIX_$(1))
|
RUNTIME_DEF_$(1)_$(2) := rt/rustrt$(CFG_DEF_SUFFIX_$(1))
|
||||||
RUNTIME_INCS_$(1) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
|
RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
|
||||||
-I $$(S)src/rt/arch/$$(HOST_$(1)) \
|
-I $$(S)src/rt/arch/$$(HOST_$(1)) \
|
||||||
-I $$(S)src/rt/linenoise \
|
-I $$(S)src/rt/linenoise \
|
||||||
-I $$(S)src/libuv/include
|
-I $$(S)src/libuv/include
|
||||||
RUNTIME_OBJS_$(1) := $$(RUNTIME_CXXS_$(1):rt/%.cpp=rt/$(1)/%.o) \
|
RUNTIME_OBJS_$(1)_$(2) := $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=rt/$(1)/stage$(2)/%.o) \
|
||||||
$$(RUNTIME_CS_$(1):rt/%.c=rt/$(1)/%.o) \
|
$$(RUNTIME_CS_$(1)_$(2):rt/%.c=rt/$(1)/stage$(2)/%.o) \
|
||||||
$$(RUNTIME_S_$(1):rt/%.S=rt/$(1)/%.o)
|
$$(RUNTIME_S_$(1)_$(2):rt/%.S=rt/$(1)/stage$(2)/%.o)
|
||||||
ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1))
|
ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
|
||||||
|
|
||||||
MORESTACK_OBJ_$(1) := rt/$(1)/arch/$$(HOST_$(1))/morestack.o
|
MORESTACK_OBJ_$(1)_$(2) := rt/$(1)/stage$(2)/arch/$$(HOST_$(1))/morestack.o
|
||||||
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1))
|
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
|
||||||
|
|
||||||
RUNTIME_LIBS_$(1) := $$(LIBUV_LIB_$(1))
|
rt/$(1)/stage$(2)/%.o: rt/%.cpp $$(MKFILE_DEPS)
|
||||||
|
|
||||||
rt/$(1)/%.o: rt/%.cpp $$(MKFILE_DEPS)
|
|
||||||
@$$(call E, compile: $$@)
|
@$$(call E, compile: $$@)
|
||||||
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
|
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
|
||||||
$$(SNAP_DEFINES)) $$<
|
$$(SNAP_DEFINES) $$(RUNTIME_CXXFLAGS_$(1)_$(2))) $$<
|
||||||
|
|
||||||
rt/$(1)/%.o: rt/%.c $$(MKFILE_DEPS)
|
rt/$(1)/stage$(2)/%.o: rt/%.c $$(MKFILE_DEPS)
|
||||||
@$$(call E, compile: $$@)
|
@$$(call E, compile: $$@)
|
||||||
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
|
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
|
||||||
$$(SNAP_DEFINES)) $$<
|
$$(SNAP_DEFINES) $$(RUNTIME_CFLAGS_$(1)_$(2))) $$<
|
||||||
|
|
||||||
rt/$(1)/%.o: rt/%.S $$(MKFILE_DEPS) \
|
rt/$(1)/stage$(2)/%.o: rt/%.S $$(MKFILE_DEPS) \
|
||||||
$$(LLVM_CONFIG_$$(CFG_BUILD_TRIPLE))
|
$$(LLVM_CONFIG_$$(CFG_BUILD_TRIPLE))
|
||||||
@$$(call E, compile: $$@)
|
@$$(call E, compile: $$@)
|
||||||
$$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
|
$$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
|
||||||
|
|
||||||
rt/$(1)/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJ_$(1))
|
rt/$(1)/stage$(2)/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJ_$(1)_$(2))
|
||||||
@$$(call E, link: $$@)
|
@$$(call E, link: $$@)
|
||||||
$$(Q)$(AR_$(1)) rcs $$@ $$<
|
$$(Q)$(AR_$(1)) rcs $$@ $$<
|
||||||
|
|
||||||
rt/$(1)/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)) $$(MKFILE_DEPS) \
|
rt/$(1)/stage$(2)/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) \
|
||||||
$$(RUNTIME_DEF_$(1)) \
|
$$(RUNTIME_DEF_$(1)_$(2)) $$(LIBUV_LIB_$(1)_$(2))
|
||||||
$$(RUNTIME_LIBS_$(1))
|
|
||||||
@$$(call E, link: $$@)
|
@$$(call E, link: $$@)
|
||||||
$$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)) \
|
$$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)_$(2)) \
|
||||||
$$(CFG_GCCISH_POST_LIB_FLAGS_$(1)) $$(RUNTIME_LIBS_$(1)) \
|
$$(CFG_GCCISH_POST_LIB_FLAGS_$(1)) $$(LIBUV_LIB_$(1)_$(2)) \
|
||||||
$$(CFG_LIBUV_LINK_FLAGS_$(1)),$$(RUNTIME_DEF_$(1)),$$(CFG_RUNTIME_$(1)))
|
$$(CFG_LIBUV_LINK_FLAGS_$(1)),$$(RUNTIME_DEF_$(1)_$(2)),$$(CFG_RUNTIME_$(1)))
|
||||||
|
|
||||||
# FIXME: For some reason libuv's makefiles can't figure out the
|
# FIXME: For some reason libuv's makefiles can't figure out the
|
||||||
# correct definition of CC on the mingw I'm using, so we are
|
# correct definition of CC on the mingw I'm using, so we are
|
||||||
@ -159,31 +181,57 @@ endif
|
|||||||
|
|
||||||
# XXX: Shouldn't need platform-specific conditions here
|
# XXX: Shouldn't need platform-specific conditions here
|
||||||
ifdef CFG_WINDOWSY_$(1)
|
ifdef CFG_WINDOWSY_$(1)
|
||||||
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
|
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
|
||||||
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
||||||
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
|
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
|
||||||
OS=mingw \
|
OS=mingw \
|
||||||
V=$$(VERBOSE)
|
V=$$(VERBOSE)
|
||||||
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
||||||
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
|
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
|
||||||
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
||||||
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
||||||
LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \
|
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
|
||||||
CC="$$(CC_$(1))" \
|
CC="$$(CC_$(1))" \
|
||||||
CXX="$$(CXX_$(1))" \
|
CXX="$$(CXX_$(1))" \
|
||||||
AR="$$(AR_$(1))" \
|
AR="$$(AR_$(1))" \
|
||||||
BUILDTYPE=Release \
|
BUILDTYPE=Release \
|
||||||
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
|
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
|
||||||
host=android OS=linux \
|
host=android OS=linux \
|
||||||
V=$$(VERBOSE)
|
V=$$(VERBOSE)
|
||||||
else
|
else
|
||||||
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
|
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
|
||||||
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
|
||||||
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
||||||
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
|
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
|
||||||
|
CC="$$(CC_$(1))" \
|
||||||
|
CXX="$$(CXX_$(1))" \
|
||||||
|
AR="$$(AR_$(1))" \
|
||||||
|
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
|
||||||
V=$$(VERBOSE)
|
V=$$(VERBOSE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
||||||
|
$$(JEMALLOC_LIB_$(1)_$(2)):
|
||||||
|
cd $$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/jemalloc; $(S)src/rt/jemalloc/configure \
|
||||||
|
--disable-experimental --build=$(CFG_BUILD_TRIPLE) --host=$(1) --disable-tls \
|
||||||
|
EXTRA_CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
||||||
|
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
|
||||||
|
CC="$$(CC_$(1))" \
|
||||||
|
CXX="$$(CXX_$(1))" \
|
||||||
|
AR="$$(AR_$(1))"
|
||||||
|
$$(Q)$$(MAKE) -C $$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/jemalloc
|
||||||
|
else
|
||||||
|
$$(JEMALLOC_LIB_$(1)_$(2)):
|
||||||
|
cd $$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/jemalloc; $(S)src/rt/jemalloc/configure \
|
||||||
|
--disable-experimental --build=$(CFG_BUILD_TRIPLE) --host=$(1) \
|
||||||
|
EXTRA_CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
|
||||||
|
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
|
||||||
|
CC="$$(CC_$(1))" \
|
||||||
|
CXX="$$(CXX_$(1))" \
|
||||||
|
AR="$$(AR_$(1))"
|
||||||
|
$$(Q)$$(MAKE) -C $$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/jemalloc
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# These could go in rt.mk or rustllvm.mk, they're needed for both.
|
# These could go in rt.mk or rustllvm.mk, they're needed for both.
|
||||||
|
|
||||||
@ -219,5 +267,6 @@ endif
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
# Instantiate template for all stages
|
# Instantiate template for all stages
|
||||||
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
$(foreach stage,$(STAGES), \
|
||||||
$(eval $(call DEF_RUNTIME_TARGETS,$(target))))
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
|
$(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
|
||||||
|
@ -22,7 +22,7 @@ LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
|
|||||||
-iquote llvm/$(1)/include
|
-iquote llvm/$(1)/include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp)
|
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp PassWrapper.cpp)
|
||||||
|
|
||||||
RUSTLLVM_DEF_$(1) := rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
|
RUSTLLVM_DEF_$(1) := rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
|
||||||
|
|
||||||
|
20
mk/stage0.mk
20
mk/stage0.mk
@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \
|
|||||||
$(S)src/etc/get-snapshot.py $(MKFILE_DEPS)
|
$(S)src/etc/get-snapshot.py $(MKFILE_DEPS)
|
||||||
@$(call E, fetch: $@)
|
@$(call E, fetch: $@)
|
||||||
# Note: the variable "SNAPSHOT_FILE" is generally not set, and so
|
# Note: the variable "SNAPSHOT_FILE" is generally not set, and so
|
||||||
# we generally only pass one argument to this script.
|
# we generally only pass one argument to this script.
|
||||||
ifdef CFG_ENABLE_LOCAL_RUST
|
ifdef CFG_ENABLE_LOCAL_RUST
|
||||||
$(Q)$(S)src/etc/local_stage0.sh $(CFG_BUILD_TRIPLE) $(CFG_LOCAL_RUST_ROOT)
|
$(Q)$(S)src/etc/local_stage0.sh $(CFG_BUILD_TRIPLE) $(CFG_LOCAL_RUST_ROOT)
|
||||||
else
|
else
|
||||||
$(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD_TRIPLE) $(SNAPSHOT_FILE)
|
$(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD_TRIPLE) $(SNAPSHOT_FILE)
|
||||||
ifdef CFG_ENABLE_PAX_FLAGS
|
ifdef CFG_ENABLE_PAX_FLAGS
|
||||||
@$(call E, apply PaX flags: $@)
|
@$(call E, apply PaX flags: $@)
|
||||||
@"$(CFG_PAXCTL)" -cm "$@"
|
@"$(CFG_PAXCTL)" -cm "$@"
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
$(Q)touch $@
|
$(Q)touch $@
|
||||||
|
|
||||||
# Host libs will be extracted by the above rule
|
# Host libs will be extracted by the above rule
|
||||||
@ -25,11 +25,11 @@ $(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)): \
|
|||||||
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
||||||
$(Q)touch $@
|
$(Q)touch $@
|
||||||
|
|
||||||
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_CORELIB_$(CFG_BUILD_TRIPLE)): \
|
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_STDLIB_$(CFG_BUILD_TRIPLE)): \
|
||||||
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
||||||
$(Q)touch $@
|
$(Q)touch $@
|
||||||
|
|
||||||
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_STDLIB_$(CFG_BUILD_TRIPLE)): \
|
$(HLIB0_H_$(CFG_BUILD_TRIPLE))/$(CFG_EXTRALIB_$(CFG_BUILD_TRIPLE)): \
|
||||||
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
$(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE))
|
||||||
$(Q)touch $@
|
$(Q)touch $@
|
||||||
|
|
||||||
@ -58,16 +58,16 @@ $$(HLIB0_H_$(1))/$(CFG_RUNTIME_$(1)): \
|
|||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(HLIB0_H_$(1))/$(CFG_CORELIB_$(1)): \
|
|
||||||
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_CORELIB_$(1))
|
|
||||||
@$$(call E, cp: $$@)
|
|
||||||
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(CORELIB_GLOB_$(1)) $$@
|
|
||||||
|
|
||||||
$$(HLIB0_H_$(1))/$(CFG_STDLIB_$(1)): \
|
$$(HLIB0_H_$(1))/$(CFG_STDLIB_$(1)): \
|
||||||
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_STDLIB_$(1))
|
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_STDLIB_$(1))
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(STDLIB_GLOB_$(1)) $$@
|
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(STDLIB_GLOB_$(1)) $$@
|
||||||
|
|
||||||
|
$$(HLIB0_H_$(1))/$(CFG_EXTRALIB_$(1)): \
|
||||||
|
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_EXTRALIB_$(1))
|
||||||
|
@$$(call E, cp: $$@)
|
||||||
|
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(EXTRALIB_GLOB_$(1)) $$@
|
||||||
|
|
||||||
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTC_$(1)): \
|
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTC_$(1)): \
|
||||||
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1))
|
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1))
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
|
65
mk/target.mk
65
mk/target.mk
@ -8,6 +8,20 @@
|
|||||||
# option. This file may not be copied, modified, or distributed
|
# option. This file may not be copied, modified, or distributed
|
||||||
# except according to those terms.
|
# except according to those terms.
|
||||||
|
|
||||||
|
# This is the compile-time target-triple for the compiler. For the compiler at
|
||||||
|
# runtime, this should be considered the host-triple. More explanation for why
|
||||||
|
# this exists can be found on issue #2400
|
||||||
|
export CFG_COMPILER_TRIPLE
|
||||||
|
|
||||||
|
# The standard libraries should be held up to a higher standard than any old
|
||||||
|
# code, make sure that these common warnings are denied by default. These can
|
||||||
|
# be overridden during development temporarily. For stage0, we allow all these
|
||||||
|
# to suppress warnings which may be bugs in stage0 (should be fixed in stage1+)
|
||||||
|
# NOTE: add "-A warnings" after snapshot to WFLAGS_ST0
|
||||||
|
WFLAGS_ST0 = -A unrecognized-lint
|
||||||
|
WFLAGS_ST1 = -D warnings
|
||||||
|
WFLAGS_ST2 = -D warnings
|
||||||
|
|
||||||
# TARGET_STAGE_N template: This defines how target artifacts are built
|
# TARGET_STAGE_N template: This defines how target artifacts are built
|
||||||
# for all stage/target architecture combinations. The arguments:
|
# for all stage/target architecture combinations. The arguments:
|
||||||
# $(1) is the stage
|
# $(1) is the stage
|
||||||
@ -18,33 +32,38 @@
|
|||||||
define TARGET_STAGE_N
|
define TARGET_STAGE_N
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
|
||||||
rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a
|
rt/$(2)/stage$(1)/arch/$$(HOST_$(2))/libmorestack.a \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \
|
||||||
rt/$(2)/$(CFG_RUNTIME_$(2))
|
rt/$(2)/stage$(1)/$(CFG_RUNTIME_$(2)) \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)): \
|
|
||||||
$$(CORELIB_CRATE) $$(CORELIB_INPUTS) \
|
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3))
|
|
||||||
@$$(call E, compile_and_link: $$@)
|
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
|
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
|
||||||
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
|
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3))
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
|
||||||
|
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
|
||||||
|
$$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
|
||||||
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
|
@$$(call E, compile_and_link: $$@)
|
||||||
|
$$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
|
||||||
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
|
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
|
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3))
|
$$(TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
|
||||||
|
|
||||||
@ -52,20 +71,24 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
|
|||||||
ifneq ($$(findstring $(2),$$(CFG_HOST_TRIPLES)),)
|
ifneq ($$(findstring $(2),$$(CFG_HOST_TRIPLES)),)
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \
|
||||||
rustllvm/$(2)/$(CFG_RUSTLLVM_$(3))
|
rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, cp: $$@)
|
@$$(call E, cp: $$@)
|
||||||
$$(Q)cp $$< $$@
|
$$(Q)cp $$< $$@
|
||||||
|
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): CFG_COMPILER_TRIPLE = $(2)
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \
|
||||||
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
|
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
|
||||||
|
| $$(TLIB$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
|
||||||
|
|
||||||
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
|
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
|
||||||
$$(DRIVER_CRATE) \
|
$$(DRIVER_CRATE) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \
|
||||||
|
| $$(TBIN$(1)_T_$(2)_H_$(3))/
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$<
|
$$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$<
|
||||||
ifdef CFG_ENABLE_PAX_FLAGS
|
ifdef CFG_ENABLE_PAX_FLAGS
|
||||||
@ -75,6 +98,14 @@ endif
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$$(TBIN$(1)_T_$(2)_H_$(3))/:
|
||||||
|
mkdir -p $$@
|
||||||
|
|
||||||
|
ifneq ($(CFG_LIBDIR),bin)
|
||||||
|
$$(TLIB$(1)_T_$(2)_H_$(3))/:
|
||||||
|
mkdir -p $$@
|
||||||
|
endif
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# In principle, each host can build each target:
|
# In principle, each host can build each target:
|
||||||
|
146
mk/tests.mk
146
mk/tests.mk
@ -14,7 +14,7 @@
|
|||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
# The names of crates that must be tested
|
# The names of crates that must be tested
|
||||||
TEST_TARGET_CRATES = core std
|
TEST_TARGET_CRATES = std extra
|
||||||
TEST_HOST_CRATES = syntax rustc rustdoc rusti rust rustpkg
|
TEST_HOST_CRATES = syntax rustc rustdoc rusti rust rustpkg
|
||||||
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
|
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
|
||||||
|
|
||||||
@ -92,6 +92,51 @@ endef
|
|||||||
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
$(eval $(call DEF_TARGET_COMMANDS,$(target))))
|
$(eval $(call DEF_TARGET_COMMANDS,$(target))))
|
||||||
|
|
||||||
|
# Target platform specific variables
|
||||||
|
# for arm-linux-androidabi
|
||||||
|
define DEF_ADB_DEVICE_STATUS
|
||||||
|
CFG_ADB_DEVICE_STATUS=$(1)
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
|
$(if $(findstring $(target),"arm-linux-androideabi"), \
|
||||||
|
$(if $(findstring adb,$(CFG_ADB)), \
|
||||||
|
$(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \
|
||||||
|
$(info check: $(target) test enabled \
|
||||||
|
$(info check: android device attached) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, true))), \
|
||||||
|
$(info check: $(target) test disabled \
|
||||||
|
$(info check: android device not attached) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, false))) \
|
||||||
|
), \
|
||||||
|
$(info check: $(target) test disabled \
|
||||||
|
$(info check: adb not found) \
|
||||||
|
$(eval $(call DEF_ADB_DEVICE_STATUS, false))) \
|
||||||
|
), \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
ifeq ($(CFG_ADB_DEVICE_STATUS),true)
|
||||||
|
CFG_ADB_TEST_DIR=/data/tmp
|
||||||
|
|
||||||
|
$(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \
|
||||||
|
$(shell adb remount 1>/dev/null) \
|
||||||
|
$(shell adb shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \
|
||||||
|
$(shell adb shell rm -rf $(CFG_ADB_TEST_DIR)/* 1>/dev/null) \
|
||||||
|
$(shell adb push $(S)src/etc/adb_run_wrapper.sh $(CFG_ADB_TEST_DIR) 1>/dev/null) \
|
||||||
|
$(shell adb push $(CFG_ANDROID_CROSS_PATH)/arm-linux-androideabi/lib/armv7-a/libgnustl_shared.so \
|
||||||
|
$(CFG_ADB_TEST_DIR) 1>/dev/null) \
|
||||||
|
$(shell adb push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD_TRIPLE))/$(CFG_RUNTIME_arm-linux-androideabi) \
|
||||||
|
$(CFG_ADB_TEST_DIR)) \
|
||||||
|
$(shell adb push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD_TRIPLE))/$(STDLIB_GLOB_arm-linux-androideabi) \
|
||||||
|
$(CFG_ADB_TEST_DIR)) \
|
||||||
|
$(shell adb push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD_TRIPLE))/$(EXTRALIB_GLOB_arm-linux-androideabi) \
|
||||||
|
$(CFG_ADB_TEST_DIR)) \
|
||||||
|
)
|
||||||
|
else
|
||||||
|
CFG_ADB_TEST_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Main test targets
|
# Main test targets
|
||||||
@ -111,7 +156,7 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
|
|||||||
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
||||||
|
|
||||||
check-lite: cleantestlibs cleantmptestlogs \
|
check-lite: cleantestlibs cleantmptestlogs \
|
||||||
check-stage2-core check-stage2-std check-stage2-rpass \
|
check-stage2-std check-stage2-extra check-stage2-rpass \
|
||||||
check-stage2-rfail check-stage2-cfail
|
check-stage2-rfail check-stage2-cfail
|
||||||
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
||||||
|
|
||||||
@ -179,9 +224,9 @@ tidy:
|
|||||||
$(Q)find $(S)src/etc -name '*.py' \
|
$(Q)find $(S)src/etc -name '*.py' \
|
||||||
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
||||||
$(Q)echo $(ALL_CS) \
|
$(Q)echo $(ALL_CS) \
|
||||||
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
||||||
$(Q)echo $(ALL_HS) \
|
$(Q)echo $(ALL_HS) \
|
||||||
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -244,58 +289,59 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
|
|||||||
|
|
||||||
define TEST_RUNNER
|
define TEST_RUNNER
|
||||||
|
|
||||||
# If NO_REBUILD is set then break the dependencies on std so we can
|
# If NO_REBUILD is set then break the dependencies on extra so we can
|
||||||
# test crates without rebuilding core and std first
|
# test crates without rebuilding std and extra first
|
||||||
ifeq ($(NO_REBUILD),)
|
ifeq ($(NO_REBUILD),)
|
||||||
STDTESTDEP_$(1)_$(2)_$(3) = $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB_$(2))
|
STDTESTDEP_$(1)_$(2)_$(3) = $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_EXTRALIB_$(2))
|
||||||
else
|
else
|
||||||
STDTESTDEP_$(1)_$(2)_$(3) =
|
STDTESTDEP_$(1)_$(2)_$(3) =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(3)/test/coretest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/stdtest-$(2)$$(X_$(2)): \
|
||||||
$$(CORELIB_CRATE) $$(CORELIB_INPUTS) \
|
|
||||||
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
|
||||||
@$$(call E, compile_and_link: $$@)
|
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
|
||||||
|
|
||||||
$(3)/test/stdtest.stage$(1)-$(2)$$(X_$(2)): \
|
|
||||||
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
|
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
|
||||||
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/syntaxtest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/extratest-$(2)$$(X_$(2)): \
|
||||||
|
$$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
|
||||||
|
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
||||||
|
@$$(call E, compile_and_link: $$@)
|
||||||
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
|
$(3)/stage$(1)/test/syntaxtest-$(2)$$(X_$(2)): \
|
||||||
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
|
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
|
||||||
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
$$(STDTESTDEP_$(1)_$(2)_$(3))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/rustctest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): CFG_COMPILER_TRIPLE = $(2)
|
||||||
|
$(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): \
|
||||||
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
|
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM_$(2)) \
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM_$(2)) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/rustpkgtest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
|
||||||
$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
|
$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/rustitest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/rustitest-$(2)$$(X_$(2)): \
|
||||||
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
|
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/rusttest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/rusttest-$(2)$$(X_$(2)): \
|
||||||
$$(RUST_LIB) $$(RUST_INPUTS) \
|
$$(RUST_LIB) $$(RUST_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
|
||||||
|
|
||||||
$(3)/test/rustdoctest.stage$(1)-$(2)$$(X_$(2)): \
|
$(3)/stage$(1)/test/rustdoctest-$(2)$$(X_$(2)): \
|
||||||
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
|
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
|
||||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
@ -312,18 +358,60 @@ define DEF_TEST_CRATE_RULES
|
|||||||
check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
|
check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
|
||||||
|
|
||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
$(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2))
|
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
|
||||||
@$$(call E, run: $$<)
|
@$$(call E, run: $$<)
|
||||||
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(2),$(3)) $$(TESTARGS) \
|
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(2),$(3)) $$(TESTARGS) \
|
||||||
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
||||||
&& touch $$@
|
&& touch $$@
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define DEF_TEST_CRATE_RULES_arm-linux-androideabi
|
||||||
|
check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
|
||||||
|
|
||||||
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
|
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
|
||||||
|
@$$(call E, run: $$< via adb)
|
||||||
|
@$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR)
|
||||||
|
@$(CFG_ADB) shell LD_LIBRARY_PATH=$(CFG_ADB_TEST_DIR) \
|
||||||
|
$(CFG_ADB_TEST_DIR)/`echo $$< | sed 's/.*\///'` \
|
||||||
|
--logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log > \
|
||||||
|
tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
|
||||||
|
@cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
|
||||||
|
@touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
|
||||||
|
@$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/
|
||||||
|
@$(CFG_ADB) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
|
||||||
|
@if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
|
||||||
|
then \
|
||||||
|
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
|
||||||
|
touch $$@; \
|
||||||
|
else \
|
||||||
|
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
|
||||||
|
exit 101; \
|
||||||
|
fi
|
||||||
|
endef
|
||||||
|
|
||||||
|
define DEF_TEST_CRATE_RULES_null
|
||||||
|
check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
|
||||||
|
|
||||||
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
|
$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2))
|
||||||
|
@$$(call E, run: skipped $$< )
|
||||||
|
@touch $$@
|
||||||
|
endef
|
||||||
|
|
||||||
$(foreach host,$(CFG_HOST_TRIPLES), \
|
$(foreach host,$(CFG_HOST_TRIPLES), \
|
||||||
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
$(foreach stage,$(STAGES), \
|
$(foreach stage,$(STAGES), \
|
||||||
$(foreach crate, $(TEST_CRATES), \
|
$(foreach crate, $(TEST_CRATES), \
|
||||||
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate)))))))
|
$(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \
|
||||||
|
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))), \
|
||||||
|
$(if $(findstring $(target),"arm-linux-androideabi"), \
|
||||||
|
$(if $(findstring $(CFG_ADB_DEVICE_STATUS),"true"), \
|
||||||
|
$(eval $(call DEF_TEST_CRATE_RULES_arm-linux-androideabi,$(stage),$(target),$(host),$(crate))), \
|
||||||
|
$(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \
|
||||||
|
), \
|
||||||
|
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \
|
||||||
|
))))))
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
@ -420,6 +508,9 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
|
|||||||
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||||
--aux-base $$(S)src/test/auxiliary/ \
|
--aux-base $$(S)src/test/auxiliary/ \
|
||||||
--stage-id stage$(1)-$(2) \
|
--stage-id stage$(1)-$(2) \
|
||||||
|
--target $(2) \
|
||||||
|
--adb-path=$(CFG_ADB) \
|
||||||
|
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
|
||||||
--rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \
|
--rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \
|
||||||
$$(CTEST_TESTARGS)
|
$$(CTEST_TESTARGS)
|
||||||
|
|
||||||
@ -454,7 +545,7 @@ ifeq ($$(CTEST_DISABLE_$(4)),)
|
|||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
|
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
|
||||||
@$$(call E, run $(4): $$<)
|
@$$(call E, run $(4) [$(2)]: $$<)
|
||||||
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
||||||
$$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
|
$$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
|
||||||
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
||||||
@ -465,7 +556,7 @@ else
|
|||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
|
$$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
|
||||||
@$$(call E, run $(4): $$<)
|
@$$(call E, run $(4) [$(2)]: $$<)
|
||||||
@$$(call E, warning: tests disabled: $$(CTEST_DISABLE_$(4)))
|
@$$(call E, warning: tests disabled: $$(CTEST_DISABLE_$(4)))
|
||||||
touch $$@
|
touch $$@
|
||||||
|
|
||||||
@ -506,7 +597,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4
|
|||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
$$(PRETTY_DEPS_$(4))
|
$$(PRETTY_DEPS_$(4))
|
||||||
@$$(call E, run pretty-rpass: $$<)
|
@$$(call E, run pretty-rpass [$(2)]: $$<)
|
||||||
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
||||||
$$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
|
$$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
|
||||||
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
|
||||||
@ -533,7 +624,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3)
|
|||||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \
|
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \
|
||||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||||
doc-$(4)-extract$(3)
|
doc-$(4)-extract$(3)
|
||||||
@$$(call E, run doc-$(4): $$<)
|
@$$(call E, run doc-$(4) [$(2)]: $$<)
|
||||||
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
||||||
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \
|
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \
|
||||||
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \
|
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \
|
||||||
@ -583,7 +674,7 @@ TEST_GROUPS = \
|
|||||||
perf \
|
perf \
|
||||||
debuginfo \
|
debuginfo \
|
||||||
doc \
|
doc \
|
||||||
$(foreach docname,$(DOC_TEST_NAMES),$(docname)) \
|
$(foreach docname,$(DOC_TEST_NAMES),doc-$(docname)) \
|
||||||
pretty \
|
pretty \
|
||||||
pretty-rpass \
|
pretty-rpass \
|
||||||
pretty-rpass-full \
|
pretty-rpass-full \
|
||||||
@ -709,4 +800,3 @@ endef
|
|||||||
|
|
||||||
$(foreach host,$(CFG_HOST_TRIPLES), \
|
$(foreach host,$(CFG_HOST_TRIPLES), \
|
||||||
$(eval $(call DEF_CHECK_FAST_FOR_H,$(host))))
|
$(eval $(call DEF_CHECK_FAST_FOR_H,$(host))))
|
||||||
|
|
||||||
|
71
mk/tools.mk
71
mk/tools.mk
@ -11,61 +11,43 @@
|
|||||||
# Rules for non-core tools built with the compiler, both for target
|
# Rules for non-core tools built with the compiler, both for target
|
||||||
# and host architectures
|
# and host architectures
|
||||||
|
|
||||||
FUZZER_LIB := $(S)src/libfuzzer/fuzzer.rc
|
|
||||||
FUZZER_INPUTS := $(wildcard $(addprefix $(S)src/libfuzzer/, *.rs))
|
|
||||||
|
|
||||||
# The test runner that runs the cfail/rfail/rpass and bxench tests
|
# The test runner that runs the cfail/rfail/rpass and bxench tests
|
||||||
COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rc
|
COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rs
|
||||||
COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*rs)
|
COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*.rs)
|
||||||
|
|
||||||
# Rustpkg, the package manager and build system
|
# Rustpkg, the package manager and build system
|
||||||
RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rc
|
RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rs
|
||||||
RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*rs)
|
RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*.rs)
|
||||||
|
|
||||||
# Rustdoc, the documentation tool
|
# Rustdoc, the documentation tool
|
||||||
RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rc
|
RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rs
|
||||||
RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
|
RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
|
||||||
|
|
||||||
# Rusti, the JIT REPL
|
# Rusti, the JIT REPL
|
||||||
RUSTI_LIB := $(S)src/librusti/rusti.rc
|
RUSTI_LIB := $(S)src/librusti/rusti.rs
|
||||||
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
|
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
|
||||||
|
|
||||||
# Rust, the convenience tool
|
# Rust, the convenience tool
|
||||||
RUST_LIB := $(S)src/librust/rust.rc
|
RUST_LIB := $(S)src/librust/rust.rs
|
||||||
RUST_INPUTS := $(wildcard $(S)src/librust/*.rs)
|
RUST_INPUTS := $(wildcard $(S)src/librust/*.rs)
|
||||||
|
|
||||||
# FIXME: These are only built for the host arch. Eventually we'll
|
# FIXME: These are only built for the host arch. Eventually we'll
|
||||||
# have tools that need to built for other targets.
|
# have tools that need to built for other targets.
|
||||||
define TOOLS_STAGE_N_TARGET
|
define TOOLS_STAGE_N_TARGET
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBFUZZER_$(4)): \
|
|
||||||
$$(FUZZER_LIB) $$(FUZZER_INPUTS) \
|
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
|
||||||
@$$(call E, compile_and_link: $$@)
|
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
|
||||||
|
|
||||||
$$(TBIN$(1)_T_$(4)_H_$(3))/fuzzer$$(X_$(4)): \
|
|
||||||
$$(DRIVER_CRATE) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBFUZZER_$(4))
|
|
||||||
@$$(call E, compile_and_link: $$@)
|
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg fuzzer -o $$@ $$<
|
|
||||||
|
|
||||||
$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)): \
|
$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)): \
|
||||||
$$(COMPILETEST_CRATE) $$(COMPILETEST_INPUTS) \
|
$$(COMPILETEST_CRATE) $$(COMPILETEST_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
|
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
|
||||||
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \
|
||||||
$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
|
$$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
||||||
@ -79,8 +61,8 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)): \
|
|||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)): \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)): \
|
||||||
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
|
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
||||||
@ -94,8 +76,8 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
|
|||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \
|
||||||
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
|
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
||||||
@ -109,8 +91,11 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \
|
|||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUST_$(4)): \
|
||||||
$$(RUST_LIB) $$(RUST_INPUTS) \
|
$$(RUST_LIB) $$(RUST_INPUTS) \
|
||||||
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
|
||||||
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
|
||||||
@$$(call E, compile_and_link: $$@)
|
@$$(call E, compile_and_link: $$@)
|
||||||
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
|
||||||
@ -125,27 +110,6 @@ endef
|
|||||||
|
|
||||||
define TOOLS_STAGE_N_HOST
|
define TOOLS_STAGE_N_HOST
|
||||||
|
|
||||||
|
|
||||||
# Promote the stageN target to stageN+1 host
|
|
||||||
# FIXME: Shouldn't need to depend on host/librustc.so once
|
|
||||||
# rpath is working
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBFUZZER_$(4)): \
|
|
||||||
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBFUZZER_$(4)) \
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
|
|
||||||
$$(HSREQ$(2)_H_$(4))
|
|
||||||
@$$(call E, cp: $$@)
|
|
||||||
$$(Q)cp $$< $$@
|
|
||||||
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBFUZZER_GLOB_$(4)) \
|
|
||||||
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBFUZZER_DSYM_GLOB_$(4))) \
|
|
||||||
$$(HLIB$(2)_H_$(4))
|
|
||||||
|
|
||||||
$$(HBIN$(2)_H_$(4))/fuzzer$$(X_$(4)): \
|
|
||||||
$$(TBIN$(1)_T_$(4)_H_$(3))/fuzzer$$(X_$(4)) \
|
|
||||||
$$(HLIB$(2)_H_$(4))/$(CFG_LIBFUZZER_$(4)) \
|
|
||||||
$$(HSREQ$(2)_H_$(4))
|
|
||||||
@$$(call E, cp: $$@)
|
|
||||||
$$(Q)cp $$< $$@
|
|
||||||
|
|
||||||
$$(HBIN$(2)_H_$(4))/compiletest$$(X_$(4)): \
|
$$(HBIN$(2)_H_$(4))/compiletest$$(X_$(4)): \
|
||||||
$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)) \
|
$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)) \
|
||||||
$$(HSREQ$(2)_H_$(4))
|
$$(HSREQ$(2)_H_$(4))
|
||||||
@ -227,7 +191,8 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
|
|||||||
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||||
$(eval $(call TOOLS_STAGE_N_TARGET,0,1,$(host),$(target))) \
|
$(eval $(call TOOLS_STAGE_N_TARGET,0,1,$(host),$(target))) \
|
||||||
$(eval $(call TOOLS_STAGE_N_TARGET,1,2,$(host),$(target))) \
|
$(eval $(call TOOLS_STAGE_N_TARGET,1,2,$(host),$(target))) \
|
||||||
$(eval $(call TOOLS_STAGE_N_TARGET,2,3,$(host),$(target)))))
|
$(eval $(call TOOLS_STAGE_N_TARGET,2,3,$(host),$(target))) \
|
||||||
|
$(eval $(call TOOLS_STAGE_N_TARGET,3,bogus,$(host),$(target)))))
|
||||||
|
|
||||||
$(foreach host,$(CFG_HOST_TRIPLES), \
|
$(foreach host,$(CFG_HOST_TRIPLES), \
|
||||||
$(eval $(call TOOLS_STAGE_N_HOST,0,1,$(host),$(host))) \
|
$(eval $(call TOOLS_STAGE_N_HOST,0,1,$(host),$(host))) \
|
||||||
|
@ -4,8 +4,8 @@ Source layout:
|
|||||||
|
|
||||||
librustc/ The self-hosted compiler
|
librustc/ The self-hosted compiler
|
||||||
|
|
||||||
libcore/ The core library (imported and linked by default)
|
libstd/ The standard library (imported and linked by default)
|
||||||
libstd/ The standard library (slightly more peripheral code)
|
libextra/ The "extras" library (slightly more peripheral code)
|
||||||
libsyntax/ The Rust parser and pretty-printer
|
libsyntax/ The Rust parser and pretty-printer
|
||||||
|
|
||||||
rt/ The runtime system
|
rt/ The runtime system
|
||||||
|
@ -66,6 +66,18 @@ pub struct config {
|
|||||||
// Run tests using the new runtime
|
// Run tests using the new runtime
|
||||||
newrt: bool,
|
newrt: bool,
|
||||||
|
|
||||||
|
// Target system to be tested
|
||||||
|
target: ~str,
|
||||||
|
|
||||||
|
// Extra parameter to run adb on arm-linux-androideabi
|
||||||
|
adb_path: ~str,
|
||||||
|
|
||||||
|
// Extra parameter to run test sute on arm-linux-androideabi
|
||||||
|
adb_test_dir: ~str,
|
||||||
|
|
||||||
|
// status whether android device available or not
|
||||||
|
adb_device_status: bool,
|
||||||
|
|
||||||
// Explain what's going on
|
// Explain what's going on
|
||||||
verbose: bool
|
verbose: bool
|
||||||
|
|
||||||
|
@ -1,235 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[crate_type = "bin"];
|
|
||||||
|
|
||||||
#[no_core];
|
|
||||||
|
|
||||||
#[allow(vecs_implicitly_copyable)];
|
|
||||||
#[allow(non_camel_case_types)];
|
|
||||||
#[allow(deprecated_mode)];
|
|
||||||
#[allow(deprecated_pattern)];
|
|
||||||
|
|
||||||
extern mod core(vers = "0.6");
|
|
||||||
extern mod std(vers = "0.6");
|
|
||||||
|
|
||||||
use core::*;
|
|
||||||
|
|
||||||
|
|
||||||
use std::getopts;
|
|
||||||
use std::test;
|
|
||||||
|
|
||||||
use core::result::{Ok, Err};
|
|
||||||
|
|
||||||
use common::config;
|
|
||||||
use common::mode_run_pass;
|
|
||||||
use common::mode_run_fail;
|
|
||||||
use common::mode_compile_fail;
|
|
||||||
use common::mode_pretty;
|
|
||||||
use common::mode_debug_info;
|
|
||||||
use common::mode;
|
|
||||||
use util::logv;
|
|
||||||
|
|
||||||
pub mod procsrv;
|
|
||||||
pub mod util;
|
|
||||||
pub mod header;
|
|
||||||
pub mod runtest;
|
|
||||||
pub mod common;
|
|
||||||
pub mod errors;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let args = os::args();
|
|
||||||
let config = parse_config(args);
|
|
||||||
log_config(config);
|
|
||||||
run_tests(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_config(args: ~[~str]) -> config {
|
|
||||||
let opts =
|
|
||||||
~[getopts::reqopt(~"compile-lib-path"),
|
|
||||||
getopts::reqopt(~"run-lib-path"),
|
|
||||||
getopts::reqopt(~"rustc-path"), getopts::reqopt(~"src-base"),
|
|
||||||
getopts::reqopt(~"build-base"), getopts::reqopt(~"aux-base"),
|
|
||||||
getopts::reqopt(~"stage-id"),
|
|
||||||
getopts::reqopt(~"mode"), getopts::optflag(~"ignored"),
|
|
||||||
getopts::optopt(~"runtool"), getopts::optopt(~"rustcflags"),
|
|
||||||
getopts::optflag(~"verbose"),
|
|
||||||
getopts::optopt(~"logfile"),
|
|
||||||
getopts::optflag(~"jit"),
|
|
||||||
getopts::optflag(~"newrt")];
|
|
||||||
|
|
||||||
assert!(!args.is_empty());
|
|
||||||
let args_ = vec::tail(args);
|
|
||||||
let matches =
|
|
||||||
&match getopts::getopts(args_, opts) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => fail!(getopts::fail_str(f))
|
|
||||||
};
|
|
||||||
|
|
||||||
fn opt_path(m: &getopts::Matches, nm: ~str) -> Path {
|
|
||||||
Path(getopts::opt_str(m, nm))
|
|
||||||
}
|
|
||||||
|
|
||||||
config {
|
|
||||||
compile_lib_path: getopts::opt_str(matches, ~"compile-lib-path"),
|
|
||||||
run_lib_path: getopts::opt_str(matches, ~"run-lib-path"),
|
|
||||||
rustc_path: opt_path(matches, ~"rustc-path"),
|
|
||||||
src_base: opt_path(matches, ~"src-base"),
|
|
||||||
build_base: opt_path(matches, ~"build-base"),
|
|
||||||
aux_base: opt_path(matches, ~"aux-base"),
|
|
||||||
stage_id: getopts::opt_str(matches, ~"stage-id"),
|
|
||||||
mode: str_mode(getopts::opt_str(matches, ~"mode")),
|
|
||||||
run_ignored: getopts::opt_present(matches, ~"ignored"),
|
|
||||||
filter:
|
|
||||||
if vec::len(matches.free) > 0u {
|
|
||||||
option::Some(matches.free[0])
|
|
||||||
} else { option::None },
|
|
||||||
logfile: getopts::opt_maybe_str(matches, ~"logfile").map(|s| Path(*s)),
|
|
||||||
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
|
|
||||||
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
|
|
||||||
jit: getopts::opt_present(matches, ~"jit"),
|
|
||||||
newrt: getopts::opt_present(matches, ~"newrt"),
|
|
||||||
verbose: getopts::opt_present(matches, ~"verbose")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log_config(config: config) {
|
|
||||||
let c = config;
|
|
||||||
logv(c, fmt!("configuration:"));
|
|
||||||
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
|
||||||
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
|
||||||
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
|
||||||
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
|
||||||
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
|
||||||
logv(c, fmt!("stage_id: %s", config.stage_id));
|
|
||||||
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
|
||||||
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
|
||||||
logv(c, fmt!("filter: %s", opt_str(config.filter)));
|
|
||||||
logv(c, fmt!("runtool: %s", opt_str(config.runtool)));
|
|
||||||
logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags)));
|
|
||||||
logv(c, fmt!("jit: %b", config.jit));
|
|
||||||
logv(c, fmt!("newrt: %b", config.newrt));
|
|
||||||
logv(c, fmt!("verbose: %b", config.verbose));
|
|
||||||
logv(c, fmt!("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn opt_str(maybestr: Option<~str>) -> ~str {
|
|
||||||
match maybestr { option::Some(s) => s, option::None => ~"(none)" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn str_opt(maybestr: ~str) -> Option<~str> {
|
|
||||||
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn str_mode(s: ~str) -> mode {
|
|
||||||
match s {
|
|
||||||
~"compile-fail" => mode_compile_fail,
|
|
||||||
~"run-fail" => mode_run_fail,
|
|
||||||
~"run-pass" => mode_run_pass,
|
|
||||||
~"pretty" => mode_pretty,
|
|
||||||
~"debug-info" => mode_debug_info,
|
|
||||||
_ => fail!(~"invalid mode")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mode_str(mode: mode) -> ~str {
|
|
||||||
match mode {
|
|
||||||
mode_compile_fail => ~"compile-fail",
|
|
||||||
mode_run_fail => ~"run-fail",
|
|
||||||
mode_run_pass => ~"run-pass",
|
|
||||||
mode_pretty => ~"pretty",
|
|
||||||
mode_debug_info => ~"debug-info",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_tests(config: config) {
|
|
||||||
let opts = test_opts(config);
|
|
||||||
let tests = make_tests(config);
|
|
||||||
let res = test::run_tests_console(&opts, tests);
|
|
||||||
if !res { fail!(~"Some tests failed"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_opts(config: config) -> test::TestOpts {
|
|
||||||
test::TestOpts {
|
|
||||||
filter: config.filter,
|
|
||||||
run_ignored: config.run_ignored,
|
|
||||||
logfile: copy config.logfile,
|
|
||||||
run_tests: true,
|
|
||||||
run_benchmarks: false,
|
|
||||||
save_results: option::None,
|
|
||||||
compare_results: option::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_tests(config: config) -> ~[test::TestDescAndFn] {
|
|
||||||
debug!("making tests from %s",
|
|
||||||
config.src_base.to_str());
|
|
||||||
let mut tests = ~[];
|
|
||||||
for os::list_dir_path(&config.src_base).each |file| {
|
|
||||||
let file = copy *file;
|
|
||||||
debug!("inspecting file %s", file.to_str());
|
|
||||||
if is_test(config, file) {
|
|
||||||
tests.push(make_test(config, file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tests
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_test(config: config, testfile: &Path) -> bool {
|
|
||||||
// Pretty-printer does not work with .rc files yet
|
|
||||||
let valid_extensions =
|
|
||||||
match config.mode {
|
|
||||||
mode_pretty => ~[~".rs"],
|
|
||||||
_ => ~[~".rc", ~".rs"]
|
|
||||||
};
|
|
||||||
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
|
||||||
let name = testfile.filename().get();
|
|
||||||
|
|
||||||
let mut valid = false;
|
|
||||||
|
|
||||||
for valid_extensions.each |ext| {
|
|
||||||
if str::ends_with(name, *ext) { valid = true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
for invalid_prefixes.each |pre| {
|
|
||||||
if str::starts_with(name, *pre) { valid = false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_test(config: config, testfile: &Path) -> test::TestDescAndFn {
|
|
||||||
test::TestDescAndFn {
|
|
||||||
desc: test::TestDesc {
|
|
||||||
name: make_test_name(config, testfile),
|
|
||||||
ignore: header::is_test_ignored(config, testfile),
|
|
||||||
should_fail: false
|
|
||||||
},
|
|
||||||
testfn: make_test_closure(config, testfile),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_test_name(config: config, testfile: &Path) -> test::TestName {
|
|
||||||
test::DynTestName(fmt!("[%s] %s",
|
|
||||||
mode_str(config.mode),
|
|
||||||
testfile.to_str()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_test_closure(config: config, testfile: &Path) -> test::TestFn {
|
|
||||||
let testfile = testfile.to_str();
|
|
||||||
test::DynTestFn(|| runtest::run(config, testfile))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local Variables:
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
275
src/compiletest/compiletest.rs
Normal file
275
src/compiletest/compiletest.rs
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[crate_type = "bin"];
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)];
|
||||||
|
|
||||||
|
#[no_core]; // XXX: Remove after snapshot
|
||||||
|
#[no_std];
|
||||||
|
|
||||||
|
extern mod core(name = "std", vers = "0.7");
|
||||||
|
extern mod extra(name = "extra", vers = "0.7");
|
||||||
|
|
||||||
|
use core::prelude::*;
|
||||||
|
use core::*;
|
||||||
|
|
||||||
|
use extra::getopts;
|
||||||
|
use extra::test;
|
||||||
|
|
||||||
|
use core::result::{Ok, Err};
|
||||||
|
|
||||||
|
use common::config;
|
||||||
|
use common::mode_run_pass;
|
||||||
|
use common::mode_run_fail;
|
||||||
|
use common::mode_compile_fail;
|
||||||
|
use common::mode_pretty;
|
||||||
|
use common::mode_debug_info;
|
||||||
|
use common::mode;
|
||||||
|
use util::logv;
|
||||||
|
|
||||||
|
pub mod procsrv;
|
||||||
|
pub mod util;
|
||||||
|
pub mod header;
|
||||||
|
pub mod runtest;
|
||||||
|
pub mod common;
|
||||||
|
pub mod errors;
|
||||||
|
|
||||||
|
mod std {
|
||||||
|
pub use core::cmp;
|
||||||
|
pub use core::str;
|
||||||
|
pub use core::sys;
|
||||||
|
pub use core::unstable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args = os::args();
|
||||||
|
let config = parse_config(args);
|
||||||
|
log_config(&config);
|
||||||
|
run_tests(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_config(args: ~[~str]) -> config {
|
||||||
|
let opts =
|
||||||
|
~[getopts::reqopt("compile-lib-path"),
|
||||||
|
getopts::reqopt("run-lib-path"),
|
||||||
|
getopts::reqopt("rustc-path"), getopts::reqopt("src-base"),
|
||||||
|
getopts::reqopt("build-base"), getopts::reqopt("aux-base"),
|
||||||
|
getopts::reqopt("stage-id"),
|
||||||
|
getopts::reqopt("mode"), getopts::optflag("ignored"),
|
||||||
|
getopts::optopt("runtool"), getopts::optopt("rustcflags"),
|
||||||
|
getopts::optflag("verbose"),
|
||||||
|
getopts::optopt("logfile"),
|
||||||
|
getopts::optflag("jit"),
|
||||||
|
getopts::optflag("newrt"),
|
||||||
|
getopts::optopt("target"),
|
||||||
|
getopts::optopt("adb-path"),
|
||||||
|
getopts::optopt("adb-test-dir")
|
||||||
|
];
|
||||||
|
|
||||||
|
assert!(!args.is_empty());
|
||||||
|
let args_ = args.tail();
|
||||||
|
let matches =
|
||||||
|
&match getopts::getopts(args_, opts) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => fail!(getopts::fail_str(f))
|
||||||
|
};
|
||||||
|
|
||||||
|
fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
|
||||||
|
Path(getopts::opt_str(m, nm))
|
||||||
|
}
|
||||||
|
|
||||||
|
config {
|
||||||
|
compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
|
||||||
|
run_lib_path: getopts::opt_str(matches, "run-lib-path"),
|
||||||
|
rustc_path: opt_path(matches, "rustc-path"),
|
||||||
|
src_base: opt_path(matches, "src-base"),
|
||||||
|
build_base: opt_path(matches, "build-base"),
|
||||||
|
aux_base: opt_path(matches, "aux-base"),
|
||||||
|
stage_id: getopts::opt_str(matches, "stage-id"),
|
||||||
|
mode: str_mode(getopts::opt_str(matches, "mode")),
|
||||||
|
run_ignored: getopts::opt_present(matches, "ignored"),
|
||||||
|
filter:
|
||||||
|
if !matches.free.is_empty() {
|
||||||
|
option::Some(copy matches.free[0])
|
||||||
|
} else { option::None },
|
||||||
|
logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)),
|
||||||
|
runtool: getopts::opt_maybe_str(matches, "runtool"),
|
||||||
|
rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
|
||||||
|
jit: getopts::opt_present(matches, "jit"),
|
||||||
|
newrt: getopts::opt_present(matches, "newrt"),
|
||||||
|
target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
|
||||||
|
adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
|
||||||
|
adb_test_dir:
|
||||||
|
opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
|
||||||
|
adb_device_status:
|
||||||
|
if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
|
||||||
|
~"arm-linux-androideabi") {
|
||||||
|
if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
|
||||||
|
~"(none)" &&
|
||||||
|
opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
|
||||||
|
~"") { true }
|
||||||
|
else { false }
|
||||||
|
} else { false },
|
||||||
|
verbose: getopts::opt_present(matches, "verbose")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_config(config: &config) {
|
||||||
|
let c = config;
|
||||||
|
logv(c, fmt!("configuration:"));
|
||||||
|
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
||||||
|
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
||||||
|
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
||||||
|
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
||||||
|
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
||||||
|
logv(c, fmt!("stage_id: %s", config.stage_id));
|
||||||
|
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
||||||
|
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
||||||
|
logv(c, fmt!("filter: %s", opt_str(&config.filter)));
|
||||||
|
logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
|
||||||
|
logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
|
||||||
|
logv(c, fmt!("jit: %b", config.jit));
|
||||||
|
logv(c, fmt!("newrt: %b", config.newrt));
|
||||||
|
logv(c, fmt!("target: %s", config.target));
|
||||||
|
logv(c, fmt!("adb_path: %s", config.adb_path));
|
||||||
|
logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
|
||||||
|
logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
|
||||||
|
logv(c, fmt!("verbose: %b", config.verbose));
|
||||||
|
logv(c, fmt!("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
|
||||||
|
match *maybestr {
|
||||||
|
option::None => "(none)",
|
||||||
|
option::Some(ref s) => {
|
||||||
|
let s: &'a str = *s;
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opt_str2(maybestr: Option<~str>) -> ~str {
|
||||||
|
match maybestr { None => ~"(none)", Some(s) => { s } }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_opt(maybestr: ~str) -> Option<~str> {
|
||||||
|
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_mode(s: ~str) -> mode {
|
||||||
|
match s {
|
||||||
|
~"compile-fail" => mode_compile_fail,
|
||||||
|
~"run-fail" => mode_run_fail,
|
||||||
|
~"run-pass" => mode_run_pass,
|
||||||
|
~"pretty" => mode_pretty,
|
||||||
|
~"debug-info" => mode_debug_info,
|
||||||
|
_ => fail!("invalid mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mode_str(mode: mode) -> ~str {
|
||||||
|
match mode {
|
||||||
|
mode_compile_fail => ~"compile-fail",
|
||||||
|
mode_run_fail => ~"run-fail",
|
||||||
|
mode_run_pass => ~"run-pass",
|
||||||
|
mode_pretty => ~"pretty",
|
||||||
|
mode_debug_info => ~"debug-info",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_tests(config: &config) {
|
||||||
|
let opts = test_opts(config);
|
||||||
|
let tests = make_tests(config);
|
||||||
|
let res = test::run_tests_console(&opts, tests);
|
||||||
|
if !res { fail!("Some tests failed"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_opts(config: &config) -> test::TestOpts {
|
||||||
|
test::TestOpts {
|
||||||
|
filter: copy config.filter,
|
||||||
|
run_ignored: config.run_ignored,
|
||||||
|
logfile: copy config.logfile,
|
||||||
|
run_tests: true,
|
||||||
|
run_benchmarks: false,
|
||||||
|
save_results: option::None,
|
||||||
|
compare_results: option::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
|
||||||
|
debug!("making tests from %s",
|
||||||
|
config.src_base.to_str());
|
||||||
|
let mut tests = ~[];
|
||||||
|
let dirs = os::list_dir_path(&config.src_base);
|
||||||
|
for dirs.iter().advance |file| {
|
||||||
|
let file = copy *file;
|
||||||
|
debug!("inspecting file %s", file.to_str());
|
||||||
|
if is_test(config, file) {
|
||||||
|
tests.push(make_test(config, file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tests
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_test(config: &config, testfile: &Path) -> bool {
|
||||||
|
// Pretty-printer does not work with .rc files yet
|
||||||
|
let valid_extensions =
|
||||||
|
match config.mode {
|
||||||
|
mode_pretty => ~[~".rs"],
|
||||||
|
_ => ~[~".rc", ~".rs"]
|
||||||
|
};
|
||||||
|
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
||||||
|
let name = testfile.filename().get();
|
||||||
|
|
||||||
|
let mut valid = false;
|
||||||
|
|
||||||
|
for valid_extensions.iter().advance |ext| {
|
||||||
|
if name.ends_with(*ext) { valid = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
for invalid_prefixes.iter().advance |pre| {
|
||||||
|
if name.starts_with(*pre) { valid = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_test(config: &config, testfile: &Path) -> test::TestDescAndFn {
|
||||||
|
test::TestDescAndFn {
|
||||||
|
desc: test::TestDesc {
|
||||||
|
name: make_test_name(config, testfile),
|
||||||
|
ignore: header::is_test_ignored(config, testfile),
|
||||||
|
should_fail: false
|
||||||
|
},
|
||||||
|
testfn: make_test_closure(config, testfile),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
|
||||||
|
|
||||||
|
// Try to elide redundant long paths
|
||||||
|
fn shorten(path: &Path) -> ~str {
|
||||||
|
let filename = path.filename();
|
||||||
|
let dir = path.pop().filename();
|
||||||
|
fmt!("%s/%s", dir.get_or_default(~""), filename.get_or_default(~""))
|
||||||
|
}
|
||||||
|
|
||||||
|
test::DynTestName(fmt!("[%s] %s",
|
||||||
|
mode_str(config.mode),
|
||||||
|
shorten(testfile)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
|
||||||
|
use core::cell::Cell;
|
||||||
|
let config = Cell::new(copy *config);
|
||||||
|
let testfile = Cell::new(testfile.to_str());
|
||||||
|
test::DynTestFn(|| { runtest::run(config.take(), testfile.take()) })
|
||||||
|
}
|
@ -11,8 +11,6 @@
|
|||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::io;
|
use core::io;
|
||||||
use core::io::ReaderUtil;
|
|
||||||
use core::str;
|
|
||||||
|
|
||||||
pub struct ExpectedError { line: uint, kind: ~str, msg: ~str }
|
pub struct ExpectedError { line: uint, kind: ~str, msg: ~str }
|
||||||
|
|
||||||
@ -23,43 +21,45 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] {
|
|||||||
let mut line_num = 1u;
|
let mut line_num = 1u;
|
||||||
while !rdr.eof() {
|
while !rdr.eof() {
|
||||||
let ln = rdr.read_line();
|
let ln = rdr.read_line();
|
||||||
error_patterns += parse_expected(line_num, ln);
|
error_patterns.push_all_move(parse_expected(line_num, ln));
|
||||||
line_num += 1u;
|
line_num += 1u;
|
||||||
}
|
}
|
||||||
return error_patterns;
|
return error_patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] {
|
fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] {
|
||||||
unsafe {
|
let error_tag = ~"//~";
|
||||||
let error_tag = ~"//~";
|
let mut idx;
|
||||||
let mut idx;
|
match line.find_str(error_tag) {
|
||||||
match str::find_str(line, error_tag) {
|
None => return ~[],
|
||||||
None => return ~[],
|
Some(nn) => { idx = (nn as uint) + error_tag.len(); }
|
||||||
Some(nn) => { idx = (nn as uint) + str::len(error_tag); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// "//~^^^ kind msg" denotes a message expected
|
|
||||||
// three lines above current line:
|
|
||||||
let mut adjust_line = 0u;
|
|
||||||
let len = str::len(line);
|
|
||||||
while idx < len && line[idx] == ('^' as u8) {
|
|
||||||
adjust_line += 1u;
|
|
||||||
idx += 1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract kind:
|
|
||||||
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
|
|
||||||
let start_kind = idx;
|
|
||||||
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
|
|
||||||
let kind = str::to_lower(str::slice(line, start_kind, idx).to_owned());
|
|
||||||
|
|
||||||
// Extract msg:
|
|
||||||
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
|
|
||||||
let msg = str::slice(line, idx, len).to_owned();
|
|
||||||
|
|
||||||
debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
|
|
||||||
|
|
||||||
return ~[ExpectedError{line: line_num - adjust_line, kind: kind,
|
|
||||||
msg: msg}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "//~^^^ kind msg" denotes a message expected
|
||||||
|
// three lines above current line:
|
||||||
|
let mut adjust_line = 0u;
|
||||||
|
let len = line.len();
|
||||||
|
while idx < len && line[idx] == ('^' as u8) {
|
||||||
|
adjust_line += 1u;
|
||||||
|
idx += 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract kind:
|
||||||
|
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
|
||||||
|
let start_kind = idx;
|
||||||
|
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
|
||||||
|
|
||||||
|
// FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
|
||||||
|
// to_ascii_consume and to_str_consume to not do a unnecessary copy.
|
||||||
|
let kind = line.slice(start_kind, idx);
|
||||||
|
let kind = kind.to_ascii().to_lower().to_str_ascii();
|
||||||
|
|
||||||
|
// Extract msg:
|
||||||
|
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
|
||||||
|
let msg = line.slice(idx, len).to_owned();
|
||||||
|
|
||||||
|
debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
|
||||||
|
|
||||||
|
return ~[ExpectedError{line: line_num - adjust_line, kind: kind,
|
||||||
|
msg: msg}];
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,11 @@
|
|||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use common;
|
|
||||||
use common::config;
|
use common::config;
|
||||||
|
use common;
|
||||||
|
|
||||||
use core::io::ReaderUtil;
|
|
||||||
use core::io;
|
use core::io;
|
||||||
use core::os;
|
use core::os;
|
||||||
use core::str;
|
|
||||||
|
|
||||||
pub struct TestProps {
|
pub struct TestProps {
|
||||||
// Lines that should be expected, in order, on standard out
|
// Lines that should be expected, in order, on standard out
|
||||||
@ -59,12 +57,14 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||||||
pp_exact = parse_pp_exact(ln, testfile);
|
pp_exact = parse_pp_exact(ln, testfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
for parse_aux_build(ln).each |ab| {
|
match parse_aux_build(ln) {
|
||||||
aux_builds.push(*ab);
|
Some(ab) => { aux_builds.push(ab); }
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for parse_exec_env(ln).each |ee| {
|
match parse_exec_env(ln) {
|
||||||
exec_env.push(*ee);
|
Some(ee) => { exec_env.push(ee); }
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match parse_debugger_cmd(ln) {
|
match parse_debugger_cmd(ln) {
|
||||||
@ -88,18 +88,17 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_test_ignored(config: config, testfile: &Path) -> bool {
|
pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
|
||||||
let mut found = false;
|
|
||||||
for iter_header(testfile) |ln| {
|
for iter_header(testfile) |ln| {
|
||||||
if parse_name_directive(ln, ~"xfail-test") { return true; }
|
if parse_name_directive(ln, "xfail-test") { return true; }
|
||||||
if parse_name_directive(ln, xfail_target()) { return true; }
|
if parse_name_directive(ln, xfail_target()) { return true; }
|
||||||
if config.mode == common::mode_pretty &&
|
if config.mode == common::mode_pretty &&
|
||||||
parse_name_directive(ln, ~"xfail-pretty") { return true; }
|
parse_name_directive(ln, "xfail-pretty") { return true; }
|
||||||
};
|
};
|
||||||
return found;
|
return false;
|
||||||
|
|
||||||
fn xfail_target() -> ~str {
|
fn xfail_target() -> ~str {
|
||||||
~"xfail-" + str::from_slice(os::SYSNAME)
|
~"xfail-" + os::SYSNAME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,52 +110,54 @@ fn iter_header(testfile: &Path, it: &fn(~str) -> bool) -> bool {
|
|||||||
// Assume that any directives will be found before the first
|
// Assume that any directives will be found before the first
|
||||||
// module or function. This doesn't seem to be an optimization
|
// module or function. This doesn't seem to be an optimization
|
||||||
// with a warm page cache. Maybe with a cold one.
|
// with a warm page cache. Maybe with a cold one.
|
||||||
if str::starts_with(ln, ~"fn")
|
if ln.starts_with("fn") || ln.starts_with("mod") {
|
||||||
|| str::starts_with(ln, ~"mod") {
|
|
||||||
return false;
|
return false;
|
||||||
} else { if !(it(ln)) { return false; } }
|
} else { if !(it(ln)) { return false; } }
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_error_pattern(line: ~str) -> Option<~str> {
|
fn parse_error_pattern(line: &str) -> Option<~str> {
|
||||||
parse_name_value_directive(line, ~"error-pattern")
|
parse_name_value_directive(line, ~"error-pattern")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_aux_build(line: ~str) -> Option<~str> {
|
fn parse_aux_build(line: &str) -> Option<~str> {
|
||||||
parse_name_value_directive(line, ~"aux-build")
|
parse_name_value_directive(line, ~"aux-build")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_compile_flags(line: ~str) -> Option<~str> {
|
fn parse_compile_flags(line: &str) -> Option<~str> {
|
||||||
parse_name_value_directive(line, ~"compile-flags")
|
parse_name_value_directive(line, ~"compile-flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_debugger_cmd(line: ~str) -> Option<~str> {
|
fn parse_debugger_cmd(line: &str) -> Option<~str> {
|
||||||
parse_name_value_directive(line, ~"debugger")
|
parse_name_value_directive(line, ~"debugger")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_check_line(line: ~str) -> Option<~str> {
|
fn parse_check_line(line: &str) -> Option<~str> {
|
||||||
parse_name_value_directive(line, ~"check")
|
parse_name_value_directive(line, ~"check")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_exec_env(line: ~str) -> Option<(~str, ~str)> {
|
fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
|
||||||
do parse_name_value_directive(line, ~"exec-env").map |nv| {
|
do parse_name_value_directive(line, ~"exec-env").map |nv| {
|
||||||
// nv is either FOO or FOO=BAR
|
// nv is either FOO or FOO=BAR
|
||||||
let mut strs = ~[];
|
let mut strs: ~[~str] = nv.splitn_iter('=', 1).transform(|s| s.to_owned()).collect();
|
||||||
for str::each_splitn_char(*nv, '=', 1u) |s| { strs.push(s.to_owned()); }
|
|
||||||
match strs.len() {
|
match strs.len() {
|
||||||
1u => (strs[0], ~""),
|
1u => (strs.pop(), ~""),
|
||||||
2u => (strs[0], strs[1]),
|
2u => {
|
||||||
n => fail!(fmt!("Expected 1 or 2 strings, not %u", n))
|
let end = strs.pop();
|
||||||
|
(strs.pop(), end)
|
||||||
|
}
|
||||||
|
n => fail!("Expected 1 or 2 strings, not %u", n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pp_exact(line: ~str, testfile: &Path) -> Option<Path> {
|
fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
|
||||||
match parse_name_value_directive(line, ~"pp-exact") {
|
match parse_name_value_directive(line, ~"pp-exact") {
|
||||||
Some(s) => Some(Path(s)),
|
Some(s) => Some(Path(s)),
|
||||||
None => {
|
None => {
|
||||||
if parse_name_directive(line, ~"pp-exact") {
|
if parse_name_directive(line, "pp-exact") {
|
||||||
Some(testfile.file_path())
|
Some(testfile.file_path())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -165,22 +166,20 @@ fn parse_pp_exact(line: ~str, testfile: &Path) -> Option<Path> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_name_directive(line: ~str, directive: ~str) -> bool {
|
fn parse_name_directive(line: &str, directive: &str) -> bool {
|
||||||
str::contains(line, directive)
|
line.contains(directive)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_name_value_directive(line: ~str,
|
fn parse_name_value_directive(line: &str,
|
||||||
directive: ~str) -> Option<~str> {
|
directive: ~str) -> Option<~str> {
|
||||||
unsafe {
|
let keycolon = directive + ":";
|
||||||
let keycolon = directive + ~":";
|
match line.find_str(keycolon) {
|
||||||
match str::find_str(line, keycolon) {
|
Some(colon) => {
|
||||||
Some(colon) => {
|
let value = line.slice(colon + keycolon.len(),
|
||||||
let value = str::slice(line, colon + str::len(keycolon),
|
line.len()).to_owned();
|
||||||
str::len(line)).to_owned();
|
debug!("%s: %s", directive, value);
|
||||||
debug!("%s: %s", directive, value);
|
Some(value)
|
||||||
Some(value)
|
|
||||||
}
|
|
||||||
None => None
|
|
||||||
}
|
}
|
||||||
|
None => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,30 +10,25 @@
|
|||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::io::{ReaderUtil, WriterUtil};
|
|
||||||
use core::io;
|
|
||||||
use core::libc::c_int;
|
|
||||||
use core::os;
|
use core::os;
|
||||||
use core::run::spawn_process;
|
|
||||||
use core::run;
|
use core::run;
|
||||||
use core::str;
|
use core::str;
|
||||||
use core::task;
|
|
||||||
|
|
||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
fn target_env(lib_path: ~str, prog: ~str) -> ~[(~str,~str)] {
|
fn target_env(lib_path: &str, prog: &str) -> ~[(~str,~str)] {
|
||||||
|
|
||||||
let mut env = os::env();
|
let mut env = os::env();
|
||||||
|
|
||||||
// Make sure we include the aux directory in the path
|
// Make sure we include the aux directory in the path
|
||||||
assert!(prog.ends_with(~".exe"));
|
assert!(prog.ends_with(".exe"));
|
||||||
let aux_path = prog.slice(0u, prog.len() - 4u) + ~".libaux";
|
let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux";
|
||||||
|
|
||||||
env = do vec::map(env) |pair| {
|
env = do env.map() |pair| {
|
||||||
let (k,v) = *pair;
|
let (k,v) = copy *pair;
|
||||||
if k == ~"PATH" { (~"PATH", v + ~";" + lib_path + ~";" + aux_path) }
|
if k == ~"PATH" { (~"PATH", v + ";" + lib_path + ";" + aux_path) }
|
||||||
else { (k,v) }
|
else { (k,v) }
|
||||||
};
|
};
|
||||||
if str::ends_with(prog, ~"rustc.exe") {
|
if prog.ends_with("rustc.exe") {
|
||||||
env.push((~"RUST_THREADS", ~"1"));
|
env.push((~"RUST_THREADS", ~"1"));
|
||||||
}
|
}
|
||||||
return env;
|
return env;
|
||||||
@ -42,87 +37,35 @@ fn target_env(lib_path: ~str, prog: ~str) -> ~[(~str,~str)] {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
fn target_env(_lib_path: ~str, _prog: ~str) -> ~[(~str,~str)] {
|
fn target_env(_lib_path: &str, _prog: &str) -> ~[(~str,~str)] {
|
||||||
~[]
|
os::env()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Result {status: int, out: ~str, err: ~str}
|
pub struct Result {status: int, out: ~str, err: ~str}
|
||||||
|
|
||||||
// FIXME (#2659): This code is duplicated in core::run::program_output
|
pub fn run(lib_path: &str,
|
||||||
pub fn run(lib_path: ~str,
|
prog: &str,
|
||||||
prog: ~str,
|
args: &[~str],
|
||||||
args: ~[~str],
|
|
||||||
env: ~[(~str, ~str)],
|
env: ~[(~str, ~str)],
|
||||||
input: Option<~str>) -> Result {
|
input: Option<~str>) -> Result {
|
||||||
let pipe_in = os::pipe();
|
|
||||||
let pipe_out = os::pipe();
|
|
||||||
let pipe_err = os::pipe();
|
|
||||||
let pid = spawn_process(prog, args,
|
|
||||||
&Some(env + target_env(lib_path, prog)),
|
|
||||||
&None, pipe_in.in, pipe_out.out, pipe_err.out);
|
|
||||||
|
|
||||||
os::close(pipe_in.in);
|
let env = env + target_env(lib_path, prog);
|
||||||
os::close(pipe_out.out);
|
let mut proc = run::Process::new(prog, args, run::ProcessOptions {
|
||||||
os::close(pipe_err.out);
|
env: Some(env.slice(0, env.len())),
|
||||||
if pid == -1i32 {
|
dir: None,
|
||||||
os::close(pipe_in.out);
|
in_fd: None,
|
||||||
os::close(pipe_out.in);
|
out_fd: None,
|
||||||
os::close(pipe_err.in);
|
err_fd: None
|
||||||
fail!();
|
});
|
||||||
|
|
||||||
|
for input.iter().advance |input| {
|
||||||
|
proc.input().write_str(*input);
|
||||||
}
|
}
|
||||||
|
let output = proc.finish_with_output();
|
||||||
|
|
||||||
|
Result {
|
||||||
writeclose(pipe_in.out, input);
|
status: output.status,
|
||||||
let p = comm::PortSet();
|
out: str::from_bytes(output.output),
|
||||||
let ch = p.chan();
|
err: str::from_bytes(output.error)
|
||||||
do task::spawn_sched(task::SingleThreaded) || {
|
|
||||||
let errput = readclose(pipe_err.in);
|
|
||||||
ch.send((2, errput));
|
|
||||||
}
|
|
||||||
let ch = p.chan();
|
|
||||||
do task::spawn_sched(task::SingleThreaded) || {
|
|
||||||
let output = readclose(pipe_out.in);
|
|
||||||
ch.send((1, output));
|
|
||||||
}
|
|
||||||
let status = run::waitpid(pid);
|
|
||||||
let mut errs = ~"";
|
|
||||||
let mut outs = ~"";
|
|
||||||
let mut count = 2;
|
|
||||||
while count > 0 {
|
|
||||||
match p.recv() {
|
|
||||||
(1, s) => {
|
|
||||||
outs = s;
|
|
||||||
}
|
|
||||||
(2, s) => {
|
|
||||||
errs = s;
|
|
||||||
}
|
|
||||||
_ => { fail!() }
|
|
||||||
};
|
|
||||||
count -= 1;
|
|
||||||
};
|
|
||||||
return Result {status: status, out: outs, err: errs};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn writeclose(fd: c_int, s: Option<~str>) {
|
|
||||||
if s.is_some() {
|
|
||||||
let writer = io::fd_writer(fd, false);
|
|
||||||
writer.write_str(s.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
os::close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readclose(fd: c_int) -> ~str {
|
|
||||||
unsafe {
|
|
||||||
// Copied from run::program_output
|
|
||||||
let file = os::fdopen(fd);
|
|
||||||
let reader = io::FILE_reader(file, false);
|
|
||||||
let mut buf = ~"";
|
|
||||||
while !reader.eof() {
|
|
||||||
let bytes = reader.read_bytes(4096u);
|
|
||||||
str::push_str(&mut buf, str::from_bytes(bytes));
|
|
||||||
}
|
|
||||||
os::fclose(file);
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,57 +22,55 @@ use procsrv;
|
|||||||
use util;
|
use util;
|
||||||
use util::logv;
|
use util::logv;
|
||||||
|
|
||||||
use core::io::WriterUtil;
|
|
||||||
use core::io;
|
use core::io;
|
||||||
use core::os;
|
use core::os;
|
||||||
use core::str;
|
|
||||||
use core::uint;
|
use core::uint;
|
||||||
use core::vec;
|
use core::vec;
|
||||||
|
|
||||||
pub fn run(config: config, testfile: ~str) {
|
pub fn run(config: config, testfile: ~str) {
|
||||||
if config.verbose {
|
if config.verbose {
|
||||||
// We're going to be dumping a lot of info. Start on a new line.
|
// We're going to be dumping a lot of info. Start on a new line.
|
||||||
io::stdout().write_str(~"\n\n");
|
io::stdout().write_str("\n\n");
|
||||||
}
|
}
|
||||||
let testfile = Path(testfile);
|
let testfile = Path(testfile);
|
||||||
debug!("running %s", testfile.to_str());
|
debug!("running %s", testfile.to_str());
|
||||||
let props = load_props(&testfile);
|
let props = load_props(&testfile);
|
||||||
debug!("loaded props");
|
debug!("loaded props");
|
||||||
match config.mode {
|
match config.mode {
|
||||||
mode_compile_fail => run_cfail_test(config, props, &testfile),
|
mode_compile_fail => run_cfail_test(&config, &props, &testfile),
|
||||||
mode_run_fail => run_rfail_test(config, props, &testfile),
|
mode_run_fail => run_rfail_test(&config, &props, &testfile),
|
||||||
mode_run_pass => run_rpass_test(config, props, &testfile),
|
mode_run_pass => run_rpass_test(&config, &props, &testfile),
|
||||||
mode_pretty => run_pretty_test(config, props, &testfile),
|
mode_pretty => run_pretty_test(&config, &props, &testfile),
|
||||||
mode_debug_info => run_debuginfo_test(config, props, &testfile)
|
mode_debug_info => run_debuginfo_test(&config, &props, &testfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_cfail_test(config: config, props: TestProps, testfile: &Path) {
|
fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||||
let ProcRes = compile_test(config, props, testfile);
|
let ProcRes = compile_test(config, props, testfile);
|
||||||
|
|
||||||
if ProcRes.status == 0 {
|
if ProcRes.status == 0 {
|
||||||
fatal_ProcRes(~"compile-fail test compiled successfully!", ProcRes);
|
fatal_ProcRes(~"compile-fail test compiled successfully!", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_correct_failure_status(ProcRes);
|
check_correct_failure_status(&ProcRes);
|
||||||
|
|
||||||
let expected_errors = errors::load_errors(testfile);
|
let expected_errors = errors::load_errors(testfile);
|
||||||
if !expected_errors.is_empty() {
|
if !expected_errors.is_empty() {
|
||||||
if !props.error_patterns.is_empty() {
|
if !props.error_patterns.is_empty() {
|
||||||
fatal(~"both error pattern and expected errors specified");
|
fatal(~"both error pattern and expected errors specified");
|
||||||
}
|
}
|
||||||
check_expected_errors(expected_errors, testfile, ProcRes);
|
check_expected_errors(expected_errors, testfile, &ProcRes);
|
||||||
} else {
|
} else {
|
||||||
check_error_patterns(props, testfile, ProcRes);
|
check_error_patterns(props, testfile, &ProcRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rfail_test(config: config, props: TestProps, testfile: &Path) {
|
fn run_rfail_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||||
let ProcRes = if !config.jit {
|
let ProcRes = if !config.jit {
|
||||||
let ProcRes = compile_test(config, props, testfile);
|
let ProcRes = compile_test(config, props, testfile);
|
||||||
|
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(~"compilation failed!", ProcRes);
|
fatal_ProcRes(~"compilation failed!", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_compiled_test(config, props, testfile)
|
exec_compiled_test(config, props, testfile)
|
||||||
@ -83,14 +81,26 @@ fn run_rfail_test(config: config, props: TestProps, testfile: &Path) {
|
|||||||
// The value our Makefile configures valgrind to return on failure
|
// The value our Makefile configures valgrind to return on failure
|
||||||
static valgrind_err: int = 100;
|
static valgrind_err: int = 100;
|
||||||
if ProcRes.status == valgrind_err {
|
if ProcRes.status == valgrind_err {
|
||||||
fatal_ProcRes(~"run-fail test isn't valgrind-clean!", ProcRes);
|
fatal_ProcRes(~"run-fail test isn't valgrind-clean!", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_correct_failure_status(ProcRes);
|
match config.target {
|
||||||
check_error_patterns(props, testfile, ProcRes);
|
|
||||||
|
~"arm-linux-androideabi" => {
|
||||||
|
if (config.adb_device_status) {
|
||||||
|
check_correct_failure_status(&ProcRes);
|
||||||
|
check_error_patterns(props, testfile, &ProcRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_=> {
|
||||||
|
check_correct_failure_status(&ProcRes);
|
||||||
|
check_error_patterns(props, testfile, &ProcRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_correct_failure_status(ProcRes: ProcRes) {
|
fn check_correct_failure_status(ProcRes: &ProcRes) {
|
||||||
// The value the rust runtime returns on failure
|
// The value the rust runtime returns on failure
|
||||||
static rust_err: int = 101;
|
static rust_err: int = 101;
|
||||||
if ProcRes.status != rust_err {
|
if ProcRes.status != rust_err {
|
||||||
@ -101,27 +111,27 @@ fn check_correct_failure_status(ProcRes: ProcRes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rpass_test(config: config, props: TestProps, testfile: &Path) {
|
fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||||
if !config.jit {
|
if !config.jit {
|
||||||
let mut ProcRes = compile_test(config, props, testfile);
|
let mut ProcRes = compile_test(config, props, testfile);
|
||||||
|
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(~"compilation failed!", ProcRes);
|
fatal_ProcRes(~"compilation failed!", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcRes = exec_compiled_test(config, props, testfile);
|
ProcRes = exec_compiled_test(config, props, testfile);
|
||||||
|
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(~"test run failed!", ProcRes);
|
fatal_ProcRes(~"test run failed!", &ProcRes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut ProcRes = jit_test(config, props, testfile);
|
let ProcRes = jit_test(config, props, testfile);
|
||||||
|
|
||||||
if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", ProcRes); }
|
if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", &ProcRes); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pretty_test(config: config, props: TestProps, testfile: &Path) {
|
fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||||
if props.pp_exact.is_some() {
|
if props.pp_exact.is_some() {
|
||||||
logv(config, ~"testing for exact pretty-printing");
|
logv(config, ~"testing for exact pretty-printing");
|
||||||
} else { logv(config, ~"testing for converging pretty-printing"); }
|
} else { logv(config, ~"testing for converging pretty-printing"); }
|
||||||
@ -134,32 +144,33 @@ fn run_pretty_test(config: config, props: TestProps, testfile: &Path) {
|
|||||||
let mut round = 0;
|
let mut round = 0;
|
||||||
while round < rounds {
|
while round < rounds {
|
||||||
logv(config, fmt!("pretty-printing round %d", round));
|
logv(config, fmt!("pretty-printing round %d", round));
|
||||||
let ProcRes = print_source(config, testfile, srcs[round]);
|
let ProcRes = print_source(config, testfile, copy srcs[round]);
|
||||||
|
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(fmt!("pretty-printing failed in round %d", round),
|
fatal_ProcRes(fmt!("pretty-printing failed in round %d", round),
|
||||||
ProcRes);
|
&ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
srcs.push(ProcRes.stdout);
|
let ProcRes{ stdout, _ } = ProcRes;
|
||||||
|
srcs.push(stdout);
|
||||||
round += 1;
|
round += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expected =
|
let mut expected =
|
||||||
match props.pp_exact {
|
match props.pp_exact {
|
||||||
Some(file) => {
|
Some(ref file) => {
|
||||||
let filepath = testfile.dir_path().push_rel(&file);
|
let filepath = testfile.dir_path().push_rel(file);
|
||||||
io::read_whole_file_str(&filepath).get()
|
io::read_whole_file_str(&filepath).get()
|
||||||
}
|
}
|
||||||
None => { srcs[vec::len(srcs) - 2u] }
|
None => { copy srcs[srcs.len() - 2u] }
|
||||||
};
|
};
|
||||||
let mut actual = srcs[vec::len(srcs) - 1u];
|
let mut actual = copy srcs[srcs.len() - 1u];
|
||||||
|
|
||||||
if props.pp_exact.is_some() {
|
if props.pp_exact.is_some() {
|
||||||
// Now we have to care about line endings
|
// Now we have to care about line endings
|
||||||
let cr = ~"\r";
|
let cr = ~"\r";
|
||||||
actual = str::replace(actual, cr, ~"");
|
actual = actual.replace(cr, "");
|
||||||
expected = str::replace(expected, cr, ~"");
|
expected = expected.replace(cr, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
compare_source(expected, actual);
|
compare_source(expected, actual);
|
||||||
@ -168,23 +179,22 @@ fn run_pretty_test(config: config, props: TestProps, testfile: &Path) {
|
|||||||
let ProcRes = typecheck_source(config, props, testfile, actual);
|
let ProcRes = typecheck_source(config, props, testfile, actual);
|
||||||
|
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(~"pretty-printed source does not typecheck", ProcRes);
|
fatal_ProcRes(~"pretty-printed source does not typecheck", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fn print_source(config: config, testfile: &Path, src: ~str) -> ProcRes {
|
fn print_source(config: &config, testfile: &Path, src: ~str) -> ProcRes {
|
||||||
compose_and_run(config, testfile, make_pp_args(config, testfile),
|
compose_and_run(config, testfile, make_pp_args(config, testfile),
|
||||||
~[], config.compile_lib_path, Some(src))
|
~[], config.compile_lib_path, Some(src))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_pp_args(config: config, _testfile: &Path) -> ProcArgs {
|
fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
|
||||||
let prog = config.rustc_path;
|
|
||||||
let args = ~[~"-", ~"--pretty", ~"normal"];
|
let args = ~[~"-", ~"--pretty", ~"normal"];
|
||||||
return ProcArgs {prog: prog.to_str(), args: args};
|
return ProcArgs {prog: config.rustc_path.to_str(), args: args};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_source(expected: ~str, actual: ~str) {
|
fn compare_source(expected: &str, actual: &str) {
|
||||||
if expected != actual {
|
if expected != actual {
|
||||||
error(~"pretty-printed source does not match expected source");
|
error(~"pretty-printed source does not match expected source");
|
||||||
let msg =
|
let msg =
|
||||||
@ -204,71 +214,70 @@ actual:\n\
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck_source(config: config, props: TestProps,
|
fn typecheck_source(config: &config, props: &TestProps,
|
||||||
testfile: &Path, src: ~str) -> ProcRes {
|
testfile: &Path, src: ~str) -> ProcRes {
|
||||||
compose_and_run_compiler(
|
let args = make_typecheck_args(config, props, testfile);
|
||||||
config, props, testfile,
|
compose_and_run_compiler(config, props, testfile, args, Some(src))
|
||||||
make_typecheck_args(config, props, testfile),
|
|
||||||
Some(src))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_typecheck_args(config: config, props: TestProps, testfile: &Path) -> ProcArgs {
|
fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
|
||||||
let prog = config.rustc_path;
|
|
||||||
let mut args = ~[~"-",
|
let mut args = ~[~"-",
|
||||||
~"--no-trans", ~"--lib",
|
~"--no-trans", ~"--lib",
|
||||||
~"-L", config.build_base.to_str(),
|
~"-L", config.build_base.to_str(),
|
||||||
~"-L",
|
~"-L",
|
||||||
aux_output_dir_name(config, testfile).to_str()];
|
aux_output_dir_name(config, testfile).to_str()];
|
||||||
args += split_maybe_args(config.rustcflags);
|
args.push_all_move(split_maybe_args(&config.rustcflags));
|
||||||
args += split_maybe_args(props.compile_flags);
|
args.push_all_move(split_maybe_args(&props.compile_flags));
|
||||||
return ProcArgs {prog: prog.to_str(), args: args};
|
return ProcArgs {prog: config.rustc_path.to_str(), args: args};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_debuginfo_test(config: config, props: TestProps, testfile: &Path) {
|
fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||||
// do not optimize debuginfo tests
|
// do not optimize debuginfo tests
|
||||||
let config = match config.rustcflags {
|
let mut config = match config.rustcflags {
|
||||||
Some(flags) => config {
|
Some(ref flags) => config {
|
||||||
rustcflags: Some(str::replace(flags, ~"-O", ~"")),
|
rustcflags: Some(flags.replace("-O", "")),
|
||||||
.. config
|
.. copy *config
|
||||||
},
|
},
|
||||||
None => config
|
None => copy *config
|
||||||
};
|
};
|
||||||
|
let config = &mut config;
|
||||||
|
let cmds = props.debugger_cmds.connect("\n");
|
||||||
|
let check_lines = copy props.check_lines;
|
||||||
|
|
||||||
// compile test file (it shoud have 'compile-flags:-g' in the header)
|
// compile test file (it shoud have 'compile-flags:-g' in the header)
|
||||||
let mut ProcRes = compile_test(config, props, testfile);
|
let mut ProcRes = compile_test(config, props, testfile);
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal_ProcRes(~"compilation failed!", ProcRes);
|
fatal_ProcRes(~"compilation failed!", &ProcRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write debugger script
|
// write debugger script
|
||||||
let script_str = str::append(str::connect(props.debugger_cmds, "\n"),
|
let script_str = cmds.append("\nquit\n");
|
||||||
~"\nquit\n");
|
|
||||||
debug!("script_str = %s", script_str);
|
debug!("script_str = %s", script_str);
|
||||||
dump_output_file(config, testfile, script_str, ~"debugger.script");
|
dump_output_file(config, testfile, script_str, "debugger.script");
|
||||||
|
|
||||||
// run debugger script with gdb
|
// run debugger script with gdb
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn debugger() -> ~str { ~"gdb.exe" }
|
fn debugger() -> ~str { ~"gdb.exe" }
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn debugger() -> ~str { ~"gdb" }
|
fn debugger() -> ~str { ~"gdb" }
|
||||||
let debugger_script = make_out_name(config, testfile, ~"debugger.script");
|
let debugger_script = make_out_name(config, testfile, "debugger.script");
|
||||||
let debugger_opts = ~[~"-quiet", ~"-batch", ~"-nx",
|
let debugger_opts = ~[~"-quiet", ~"-batch", ~"-nx",
|
||||||
~"-command=" + debugger_script.to_str(),
|
~"-command=" + debugger_script.to_str(),
|
||||||
make_exe_name(config, testfile).to_str()];
|
make_exe_name(config, testfile).to_str()];
|
||||||
let ProcArgs = ProcArgs {prog: debugger(), args: debugger_opts};
|
let ProcArgs = ProcArgs {prog: debugger(), args: debugger_opts};
|
||||||
ProcRes = compose_and_run(config, testfile, ProcArgs, ~[], ~"", None);
|
ProcRes = compose_and_run(config, testfile, ProcArgs, ~[], "", None);
|
||||||
if ProcRes.status != 0 {
|
if ProcRes.status != 0 {
|
||||||
fatal(~"gdb failed to execute");
|
fatal(~"gdb failed to execute");
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_check_lines = vec::len(props.check_lines);
|
let num_check_lines = check_lines.len();
|
||||||
if num_check_lines > 0 {
|
if num_check_lines > 0 {
|
||||||
// check if each line in props.check_lines appears in the
|
// check if each line in props.check_lines appears in the
|
||||||
// output (in order)
|
// output (in order)
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
for str::each_line(ProcRes.stdout) |line| {
|
for ProcRes.stdout.line_iter().advance |line| {
|
||||||
if props.check_lines[i].trim() == line.trim() {
|
if check_lines[i].trim() == line.trim() {
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
if i == num_check_lines {
|
if i == num_check_lines {
|
||||||
@ -278,15 +287,15 @@ fn run_debuginfo_test(config: config, props: TestProps, testfile: &Path) {
|
|||||||
}
|
}
|
||||||
if i != num_check_lines {
|
if i != num_check_lines {
|
||||||
fatal_ProcRes(fmt!("line not found in debugger output: %s"
|
fatal_ProcRes(fmt!("line not found in debugger output: %s"
|
||||||
props.check_lines[i]), ProcRes);
|
check_lines[i]), &ProcRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_error_patterns(props: TestProps,
|
fn check_error_patterns(props: &TestProps,
|
||||||
testfile: &Path,
|
testfile: &Path,
|
||||||
ProcRes: ProcRes) {
|
ProcRes: &ProcRes) {
|
||||||
if vec::is_empty(props.error_patterns) {
|
if props.error_patterns.is_empty() {
|
||||||
fatal(~"no error pattern specified in " + testfile.to_str());
|
fatal(~"no error pattern specified in " + testfile.to_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,30 +304,29 @@ fn check_error_patterns(props: TestProps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut next_err_idx = 0u;
|
let mut next_err_idx = 0u;
|
||||||
let mut next_err_pat = props.error_patterns[next_err_idx];
|
let mut next_err_pat = &props.error_patterns[next_err_idx];
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
for str::each_line(ProcRes.stderr) |line| {
|
for ProcRes.stderr.line_iter().advance |line| {
|
||||||
if str::contains(line, next_err_pat) {
|
if line.contains(*next_err_pat) {
|
||||||
debug!("found error pattern %s", next_err_pat);
|
debug!("found error pattern %s", *next_err_pat);
|
||||||
next_err_idx += 1u;
|
next_err_idx += 1u;
|
||||||
if next_err_idx == vec::len(props.error_patterns) {
|
if next_err_idx == props.error_patterns.len() {
|
||||||
debug!("found all error patterns");
|
debug!("found all error patterns");
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
next_err_pat = props.error_patterns[next_err_idx];
|
next_err_pat = &props.error_patterns[next_err_idx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if done { return; }
|
if done { return; }
|
||||||
|
|
||||||
let missing_patterns =
|
let missing_patterns =
|
||||||
vec::slice(props.error_patterns, next_err_idx,
|
props.error_patterns.slice(next_err_idx, props.error_patterns.len());
|
||||||
vec::len(props.error_patterns));
|
if missing_patterns.len() == 1u {
|
||||||
if vec::len(missing_patterns) == 1u {
|
|
||||||
fatal_ProcRes(fmt!("error pattern '%s' not found!",
|
fatal_ProcRes(fmt!("error pattern '%s' not found!",
|
||||||
missing_patterns[0]), ProcRes);
|
missing_patterns[0]), ProcRes);
|
||||||
} else {
|
} else {
|
||||||
for missing_patterns.each |pattern| {
|
for missing_patterns.iter().advance |pattern| {
|
||||||
error(fmt!("error pattern '%s' not found!", *pattern));
|
error(fmt!("error pattern '%s' not found!", *pattern));
|
||||||
}
|
}
|
||||||
fatal_ProcRes(~"multiple error patterns not found", ProcRes);
|
fatal_ProcRes(~"multiple error patterns not found", ProcRes);
|
||||||
@ -327,19 +335,19 @@ fn check_error_patterns(props: TestProps,
|
|||||||
|
|
||||||
fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
|
fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
|
||||||
testfile: &Path,
|
testfile: &Path,
|
||||||
ProcRes: ProcRes) {
|
ProcRes: &ProcRes) {
|
||||||
|
|
||||||
// true if we found the error in question
|
// true if we found the error in question
|
||||||
let mut found_flags = vec::from_elem(
|
let mut found_flags = vec::from_elem(
|
||||||
vec::len(expected_errors), false);
|
expected_errors.len(), false);
|
||||||
|
|
||||||
if ProcRes.status == 0 {
|
if ProcRes.status == 0 {
|
||||||
fatal(~"process did not return an error status");
|
fatal(~"process did not return an error status");
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefixes = vec::map(expected_errors, |ee| {
|
let prefixes = expected_errors.iter().transform(|ee| {
|
||||||
fmt!("%s:%u:", testfile.to_str(), ee.line)
|
fmt!("%s:%u:", testfile.to_str(), ee.line)
|
||||||
});
|
}).collect::<~[~str]>();
|
||||||
|
|
||||||
// Scan and extract our error/warning messages,
|
// Scan and extract our error/warning messages,
|
||||||
// which look like:
|
// which look like:
|
||||||
@ -347,15 +355,15 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
|
|||||||
// filename:line1:col1: line2:col2: *warning:* msg
|
// filename:line1:col1: line2:col2: *warning:* msg
|
||||||
// where line1:col1: is the starting point, line2:col2:
|
// where line1:col1: is the starting point, line2:col2:
|
||||||
// is the ending point, and * represents ANSI color codes.
|
// is the ending point, and * represents ANSI color codes.
|
||||||
for str::each_line(ProcRes.stderr) |line| {
|
for ProcRes.stderr.line_iter().advance |line| {
|
||||||
let mut was_expected = false;
|
let mut was_expected = false;
|
||||||
for vec::eachi(expected_errors) |i, ee| {
|
for expected_errors.iter().enumerate().advance |(i, ee)| {
|
||||||
if !found_flags[i] {
|
if !found_flags[i] {
|
||||||
debug!("prefix=%s ee.kind=%s ee.msg=%s line=%s",
|
debug!("prefix=%s ee.kind=%s ee.msg=%s line=%s",
|
||||||
prefixes[i], ee.kind, ee.msg, line);
|
prefixes[i], ee.kind, ee.msg, line);
|
||||||
if (str::starts_with(line, prefixes[i]) &&
|
if (line.starts_with(prefixes[i]) &&
|
||||||
str::contains(line, ee.kind) &&
|
line.contains(ee.kind) &&
|
||||||
str::contains(line, ee.msg)) {
|
line.contains(ee.msg)) {
|
||||||
found_flags[i] = true;
|
found_flags[i] = true;
|
||||||
was_expected = true;
|
was_expected = true;
|
||||||
break;
|
break;
|
||||||
@ -364,27 +372,27 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ignore this msg which gets printed at the end
|
// ignore this msg which gets printed at the end
|
||||||
if str::contains(line, ~"aborting due to") {
|
if line.contains("aborting due to") {
|
||||||
was_expected = true;
|
was_expected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !was_expected && is_compiler_error_or_warning(str::from_slice(line)) {
|
if !was_expected && is_compiler_error_or_warning(line) {
|
||||||
fatal_ProcRes(fmt!("unexpected compiler error or warning: '%s'",
|
fatal_ProcRes(fmt!("unexpected compiler error or warning: '%s'",
|
||||||
line),
|
line),
|
||||||
ProcRes);
|
ProcRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for uint::range(0u, vec::len(found_flags)) |i| {
|
for uint::range(0u, found_flags.len()) |i| {
|
||||||
if !found_flags[i] {
|
if !found_flags[i] {
|
||||||
let ee = expected_errors[i];
|
let ee = &expected_errors[i];
|
||||||
fatal_ProcRes(fmt!("expected %s on line %u not found: %s",
|
fatal_ProcRes(fmt!("expected %s on line %u not found: %s",
|
||||||
ee.kind, ee.line, ee.msg), ProcRes);
|
ee.kind, ee.line, ee.msg), ProcRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_compiler_error_or_warning(line: ~str) -> bool {
|
fn is_compiler_error_or_warning(line: &str) -> bool {
|
||||||
let mut i = 0u;
|
let mut i = 0u;
|
||||||
return
|
return
|
||||||
scan_until_char(line, ':', &mut i) &&
|
scan_until_char(line, ':', &mut i) &&
|
||||||
@ -398,15 +406,15 @@ fn is_compiler_error_or_warning(line: ~str) -> bool {
|
|||||||
scan_char(line, ':', &mut i) &&
|
scan_char(line, ':', &mut i) &&
|
||||||
scan_integer(line, &mut i) &&
|
scan_integer(line, &mut i) &&
|
||||||
scan_char(line, ' ', &mut i) &&
|
scan_char(line, ' ', &mut i) &&
|
||||||
(scan_string(line, ~"error", &mut i) ||
|
(scan_string(line, "error", &mut i) ||
|
||||||
scan_string(line, ~"warning", &mut i));
|
scan_string(line, "warning", &mut i));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_until_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
|
fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
|
||||||
if *idx >= haystack.len() {
|
if *idx >= haystack.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let opt = str::find_char_from(haystack, needle, *idx);
|
let opt = haystack.slice_from(*idx).find(needle);
|
||||||
if opt.is_none() {
|
if opt.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -414,11 +422,11 @@ fn scan_until_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
|
fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
|
||||||
if *idx >= haystack.len() {
|
if *idx >= haystack.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let range = str::char_range_at(haystack, *idx);
|
let range = haystack.char_range_at(*idx);
|
||||||
if range.ch != needle {
|
if range.ch != needle {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -426,10 +434,10 @@ fn scan_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_integer(haystack: ~str, idx: &mut uint) -> bool {
|
fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
|
||||||
let mut i = *idx;
|
let mut i = *idx;
|
||||||
while i < haystack.len() {
|
while i < haystack.len() {
|
||||||
let range = str::char_range_at(haystack, i);
|
let range = haystack.char_range_at(i);
|
||||||
if range.ch < '0' || '9' < range.ch {
|
if range.ch < '0' || '9' < range.ch {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -442,14 +450,14 @@ fn scan_integer(haystack: ~str, idx: &mut uint) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_string(haystack: ~str, needle: ~str, idx: &mut uint) -> bool {
|
fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
|
||||||
let mut haystack_i = *idx;
|
let mut haystack_i = *idx;
|
||||||
let mut needle_i = 0u;
|
let mut needle_i = 0u;
|
||||||
while needle_i < needle.len() {
|
while needle_i < needle.len() {
|
||||||
if haystack_i >= haystack.len() {
|
if haystack_i >= haystack.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let range = str::char_range_at(haystack, haystack_i);
|
let range = haystack.char_range_at(haystack_i);
|
||||||
haystack_i = range.next;
|
haystack_i = range.next;
|
||||||
if !scan_char(needle, range.ch, &mut needle_i) {
|
if !scan_char(needle, range.ch, &mut needle_i) {
|
||||||
return false;
|
return false;
|
||||||
@ -463,44 +471,52 @@ struct ProcArgs {prog: ~str, args: ~[~str]}
|
|||||||
|
|
||||||
struct ProcRes {status: int, stdout: ~str, stderr: ~str, cmdline: ~str}
|
struct ProcRes {status: int, stdout: ~str, stderr: ~str, cmdline: ~str}
|
||||||
|
|
||||||
fn compile_test(config: config, props: TestProps,
|
fn compile_test(config: &config, props: &TestProps,
|
||||||
testfile: &Path) -> ProcRes {
|
testfile: &Path) -> ProcRes {
|
||||||
compile_test_(config, props, testfile, [])
|
compile_test_(config, props, testfile, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jit_test(config: config, props: TestProps, testfile: &Path) -> ProcRes {
|
fn jit_test(config: &config, props: &TestProps, testfile: &Path) -> ProcRes {
|
||||||
compile_test_(config, props, testfile, [~"--jit"])
|
compile_test_(config, props, testfile, [~"--jit"])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_test_(config: config, props: TestProps,
|
fn compile_test_(config: &config, props: &TestProps,
|
||||||
testfile: &Path, extra_args: &[~str]) -> ProcRes {
|
testfile: &Path, extra_args: &[~str]) -> ProcRes {
|
||||||
let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
|
let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
|
||||||
compose_and_run_compiler(
|
let args = make_compile_args(config, props, link_args + extra_args,
|
||||||
config, props, testfile,
|
make_exe_name, testfile);
|
||||||
make_compile_args(config, props, link_args + extra_args,
|
compose_and_run_compiler(config, props, testfile, args, None)
|
||||||
make_exe_name, testfile),
|
|
||||||
None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_compiled_test(config: config, props: TestProps,
|
fn exec_compiled_test(config: &config, props: &TestProps,
|
||||||
testfile: &Path) -> ProcRes {
|
testfile: &Path) -> ProcRes {
|
||||||
|
|
||||||
// If testing the new runtime then set the RUST_NEWRT env var
|
// If testing the new runtime then set the RUST_NEWRT env var
|
||||||
let env = if config.newrt {
|
let env = copy props.exec_env;
|
||||||
props.exec_env + ~[(~"RUST_NEWRT", ~"1")]
|
let env = if config.newrt { env + &[(~"RUST_NEWRT", ~"1")] } else { env };
|
||||||
} else {
|
|
||||||
props.exec_env
|
|
||||||
};
|
|
||||||
|
|
||||||
compose_and_run(config, testfile,
|
match config.target {
|
||||||
make_run_args(config, props, testfile),
|
|
||||||
env,
|
~"arm-linux-androideabi" => {
|
||||||
config.run_lib_path, None)
|
if (config.adb_device_status) {
|
||||||
|
_arm_exec_compiled_test(config, props, testfile)
|
||||||
|
} else {
|
||||||
|
_dummy_exec_compiled_test(config, props, testfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_=> {
|
||||||
|
compose_and_run(config, testfile,
|
||||||
|
make_run_args(config, props, testfile),
|
||||||
|
env,
|
||||||
|
config.run_lib_path, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compose_and_run_compiler(
|
fn compose_and_run_compiler(
|
||||||
config: config,
|
config: &config,
|
||||||
props: TestProps,
|
props: &TestProps,
|
||||||
testfile: &Path,
|
testfile: &Path,
|
||||||
args: ProcArgs,
|
args: ProcArgs,
|
||||||
input: Option<~str>) -> ProcRes {
|
input: Option<~str>) -> ProcRes {
|
||||||
@ -512,7 +528,7 @@ fn compose_and_run_compiler(
|
|||||||
let extra_link_args = ~[~"-L",
|
let extra_link_args = ~[~"-L",
|
||||||
aux_output_dir_name(config, testfile).to_str()];
|
aux_output_dir_name(config, testfile).to_str()];
|
||||||
|
|
||||||
for vec::each(props.aux_builds) |rel_ab| {
|
for props.aux_builds.iter().advance |rel_ab| {
|
||||||
let abs_ab = config.aux_base.push_rel(&Path(*rel_ab));
|
let abs_ab = config.aux_base.push_rel(&Path(*rel_ab));
|
||||||
let aux_args =
|
let aux_args =
|
||||||
make_compile_args(config, props, ~[~"--lib"] + extra_link_args,
|
make_compile_args(config, props, ~[~"--lib"] + extra_link_args,
|
||||||
@ -523,7 +539,18 @@ fn compose_and_run_compiler(
|
|||||||
fatal_ProcRes(
|
fatal_ProcRes(
|
||||||
fmt!("auxiliary build of %s failed to compile: ",
|
fmt!("auxiliary build of %s failed to compile: ",
|
||||||
abs_ab.to_str()),
|
abs_ab.to_str()),
|
||||||
auxres);
|
&auxres);
|
||||||
|
}
|
||||||
|
|
||||||
|
match config.target {
|
||||||
|
|
||||||
|
~"arm-linux-androideabi" => {
|
||||||
|
if (config.adb_device_status) {
|
||||||
|
_arm_push_aux_shared_library(config, testfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_=> { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,78 +561,65 @@ fn compose_and_run_compiler(
|
|||||||
fn ensure_dir(path: &Path) {
|
fn ensure_dir(path: &Path) {
|
||||||
if os::path_is_dir(path) { return; }
|
if os::path_is_dir(path) { return; }
|
||||||
if !os::make_dir(path, 0x1c0i32) {
|
if !os::make_dir(path, 0x1c0i32) {
|
||||||
fail!(fmt!("can't make dir %s", path.to_str()));
|
fail!("can't make dir %s", path.to_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compose_and_run(config: config, testfile: &Path,
|
fn compose_and_run(config: &config, testfile: &Path,
|
||||||
ProcArgs: ProcArgs,
|
ProcArgs{ args, prog }: ProcArgs,
|
||||||
procenv: ~[(~str, ~str)],
|
procenv: ~[(~str, ~str)],
|
||||||
lib_path: ~str,
|
lib_path: &str,
|
||||||
input: Option<~str>) -> ProcRes {
|
input: Option<~str>) -> ProcRes {
|
||||||
return program_output(config, testfile, lib_path,
|
return program_output(config, testfile, lib_path,
|
||||||
ProcArgs.prog, ProcArgs.args, procenv, input);
|
prog, args, procenv, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_compile_args(config: config, props: TestProps, extras: ~[~str],
|
fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str],
|
||||||
xform: &fn(config, (&Path)) -> Path,
|
xform: &fn(&config, (&Path)) -> Path,
|
||||||
testfile: &Path) -> ProcArgs {
|
testfile: &Path) -> ProcArgs {
|
||||||
let prog = config.rustc_path;
|
|
||||||
let mut args = ~[testfile.to_str(),
|
let mut args = ~[testfile.to_str(),
|
||||||
~"-o", xform(config, testfile).to_str(),
|
~"-o", xform(config, testfile).to_str(),
|
||||||
~"-L", config.build_base.to_str()]
|
~"-L", config.build_base.to_str()]
|
||||||
+ extras;
|
+ extras;
|
||||||
args += split_maybe_args(config.rustcflags);
|
args.push_all_move(split_maybe_args(&config.rustcflags));
|
||||||
args += split_maybe_args(props.compile_flags);
|
args.push_all_move(split_maybe_args(&props.compile_flags));
|
||||||
return ProcArgs {prog: prog.to_str(), args: args};
|
return ProcArgs {prog: config.rustc_path.to_str(), args: args};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_lib_name(config: config, auxfile: &Path, testfile: &Path) -> Path {
|
fn make_lib_name(config: &config, auxfile: &Path, testfile: &Path) -> Path {
|
||||||
// what we return here is not particularly important, as it
|
// what we return here is not particularly important, as it
|
||||||
// happens; rustc ignores everything except for the directory.
|
// happens; rustc ignores everything except for the directory.
|
||||||
let auxname = output_testname(auxfile);
|
let auxname = output_testname(auxfile);
|
||||||
aux_output_dir_name(config, testfile).push_rel(&auxname)
|
aux_output_dir_name(config, testfile).push_rel(&auxname)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_exe_name(config: config, testfile: &Path) -> Path {
|
fn make_exe_name(config: &config, testfile: &Path) -> Path {
|
||||||
Path(output_base_name(config, testfile).to_str() +
|
Path(output_base_name(config, testfile).to_str() + os::EXE_SUFFIX)
|
||||||
str::from_slice(os::EXE_SUFFIX))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run_args(config: config, _props: TestProps, testfile: &Path) ->
|
fn make_run_args(config: &config, _props: &TestProps, testfile: &Path) ->
|
||||||
ProcArgs {
|
ProcArgs {
|
||||||
let toolargs = {
|
// If we've got another tool to run under (valgrind),
|
||||||
// If we've got another tool to run under (valgrind),
|
// then split apart its command
|
||||||
// then split apart its command
|
let toolargs = split_maybe_args(&config.runtool);
|
||||||
let runtool =
|
|
||||||
match config.runtool {
|
|
||||||
Some(s) => Some(s),
|
|
||||||
None => None
|
|
||||||
};
|
|
||||||
split_maybe_args(runtool)
|
|
||||||
};
|
|
||||||
|
|
||||||
let args = toolargs + ~[make_exe_name(config, testfile).to_str()];
|
let mut args = toolargs + [make_exe_name(config, testfile).to_str()];
|
||||||
return ProcArgs {prog: args[0],
|
let prog = args.shift();
|
||||||
args: vec::slice(args, 1, args.len()).to_vec()};
|
return ProcArgs {prog: prog, args: args};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_maybe_args(argstr: Option<~str>) -> ~[~str] {
|
fn split_maybe_args(argstr: &Option<~str>) -> ~[~str] {
|
||||||
fn rm_whitespace(v: ~[~str]) -> ~[~str] {
|
match *argstr {
|
||||||
v.filtered(|s| !str::is_whitespace(*s))
|
Some(ref s) => {
|
||||||
}
|
s.split_iter(' ')
|
||||||
|
.filter_map(|s| if s.is_whitespace() {None} else {Some(s.to_owned())})
|
||||||
match argstr {
|
.collect()
|
||||||
Some(s) => {
|
|
||||||
let mut ss = ~[];
|
|
||||||
for str::each_split_char(s, ' ') |s| { ss.push(s.to_owned()) }
|
|
||||||
rm_whitespace(ss)
|
|
||||||
}
|
}
|
||||||
None => ~[]
|
None => ~[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_output(config: config, testfile: &Path, lib_path: ~str, prog: ~str,
|
fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str,
|
||||||
args: ~[~str], env: ~[(~str, ~str)],
|
args: ~[~str], env: ~[(~str, ~str)],
|
||||||
input: Option<~str>) -> ProcRes {
|
input: Option<~str>) -> ProcRes {
|
||||||
let cmdline =
|
let cmdline =
|
||||||
@ -614,11 +628,12 @@ fn program_output(config: config, testfile: &Path, lib_path: ~str, prog: ~str,
|
|||||||
logv(config, fmt!("executing %s", cmdline));
|
logv(config, fmt!("executing %s", cmdline));
|
||||||
cmdline
|
cmdline
|
||||||
};
|
};
|
||||||
let res = procsrv::run(lib_path, prog, args, env, input);
|
let procsrv::Result{ out, err, status } =
|
||||||
dump_output(config, testfile, res.out, res.err);
|
procsrv::run(lib_path, prog, args, env, input);
|
||||||
return ProcRes {status: res.status,
|
dump_output(config, testfile, out, err);
|
||||||
stdout: res.out,
|
return ProcRes {status: status,
|
||||||
stderr: res.err,
|
stdout: out,
|
||||||
|
stderr: err,
|
||||||
cmdline: cmdline};
|
cmdline: cmdline};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,41 +641,41 @@ fn program_output(config: config, testfile: &Path, lib_path: ~str, prog: ~str,
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
fn make_cmdline(_libpath: ~str, prog: ~str, args: ~[~str]) -> ~str {
|
fn make_cmdline(_libpath: &str, prog: &str, args: &[~str]) -> ~str {
|
||||||
fmt!("%s %s", prog, str::connect(args, ~" "))
|
fmt!("%s %s", prog, args.connect(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
fn make_cmdline(libpath: ~str, prog: ~str, args: ~[~str]) -> ~str {
|
fn make_cmdline(libpath: &str, prog: &str, args: &[~str]) -> ~str {
|
||||||
fmt!("%s %s %s", lib_path_cmd_prefix(libpath), prog,
|
fmt!("%s %s %s", lib_path_cmd_prefix(libpath), prog,
|
||||||
str::connect(args, ~" "))
|
args.connect(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
|
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
|
||||||
// for diagnostic purposes
|
// for diagnostic purposes
|
||||||
fn lib_path_cmd_prefix(path: ~str) -> ~str {
|
fn lib_path_cmd_prefix(path: &str) -> ~str {
|
||||||
fmt!("%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path))
|
fmt!("%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_output(config: config, testfile: &Path, out: ~str, err: ~str) {
|
fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) {
|
||||||
dump_output_file(config, testfile, out, ~"out");
|
dump_output_file(config, testfile, out, "out");
|
||||||
dump_output_file(config, testfile, err, ~"err");
|
dump_output_file(config, testfile, err, "err");
|
||||||
maybe_dump_to_stdout(config, out, err);
|
maybe_dump_to_stdout(config, out, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_output_file(config: config, testfile: &Path,
|
fn dump_output_file(config: &config, testfile: &Path,
|
||||||
out: ~str, extension: ~str) {
|
out: &str, extension: &str) {
|
||||||
let outfile = make_out_name(config, testfile, extension);
|
let outfile = make_out_name(config, testfile, extension);
|
||||||
let writer =
|
let writer =
|
||||||
io::file_writer(&outfile, ~[io::Create, io::Truncate]).get();
|
io::file_writer(&outfile, [io::Create, io::Truncate]).get();
|
||||||
writer.write_str(out);
|
writer.write_str(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_out_name(config: config, testfile: &Path, extension: ~str) -> Path {
|
fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path {
|
||||||
output_base_name(config, testfile).with_filetype(extension)
|
output_base_name(config, testfile).with_filetype(extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aux_output_dir_name(config: config, testfile: &Path) -> Path {
|
fn aux_output_dir_name(config: &config, testfile: &Path) -> Path {
|
||||||
output_base_name(config, testfile).with_filetype("libaux")
|
output_base_name(config, testfile).with_filetype("libaux")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,16 +683,16 @@ fn output_testname(testfile: &Path) -> Path {
|
|||||||
Path(testfile.filestem().get())
|
Path(testfile.filestem().get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_base_name(config: config, testfile: &Path) -> Path {
|
fn output_base_name(config: &config, testfile: &Path) -> Path {
|
||||||
config.build_base
|
config.build_base
|
||||||
.push_rel(&output_testname(testfile))
|
.push_rel(&output_testname(testfile))
|
||||||
.with_filetype(config.stage_id)
|
.with_filetype(config.stage_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_dump_to_stdout(config: config, out: ~str, err: ~str) {
|
fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
|
||||||
if config.verbose {
|
if config.verbose {
|
||||||
let sep1 = fmt!("------%s------------------------------", ~"stdout");
|
let sep1 = fmt!("------%s------------------------------", "stdout");
|
||||||
let sep2 = fmt!("------%s------------------------------", ~"stderr");
|
let sep2 = fmt!("------%s------------------------------", "stderr");
|
||||||
let sep3 = ~"------------------------------------------";
|
let sep3 = ~"------------------------------------------";
|
||||||
io::stdout().write_line(sep1);
|
io::stdout().write_line(sep1);
|
||||||
io::stdout().write_line(out);
|
io::stdout().write_line(out);
|
||||||
@ -691,7 +706,7 @@ fn error(err: ~str) { io::stdout().write_line(fmt!("\nerror: %s", err)); }
|
|||||||
|
|
||||||
fn fatal(err: ~str) -> ! { error(err); fail!(); }
|
fn fatal(err: ~str) -> ! { error(err); fail!(); }
|
||||||
|
|
||||||
fn fatal_ProcRes(err: ~str, ProcRes: ProcRes) -> ! {
|
fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! {
|
||||||
let msg =
|
let msg =
|
||||||
fmt!("\n\
|
fmt!("\n\
|
||||||
error: %s\n\
|
error: %s\n\
|
||||||
@ -709,3 +724,117 @@ stderr:\n\
|
|||||||
io::stdout().write_str(msg);
|
io::stdout().write_str(msg);
|
||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _arm_exec_compiled_test(config: &config, props: &TestProps,
|
||||||
|
testfile: &Path) -> ProcRes {
|
||||||
|
|
||||||
|
let args = make_run_args(config, props, testfile);
|
||||||
|
let cmdline = make_cmdline("", args.prog, args.args);
|
||||||
|
|
||||||
|
// get bare program string
|
||||||
|
let mut tvec: ~[~str] = args.prog.split_iter('/').transform(|ts| ts.to_owned()).collect();
|
||||||
|
let prog_short = tvec.pop();
|
||||||
|
|
||||||
|
// copy to target
|
||||||
|
let copy_result = procsrv::run("", config.adb_path,
|
||||||
|
[~"push", copy args.prog, copy config.adb_test_dir],
|
||||||
|
~[(~"",~"")], Some(~""));
|
||||||
|
|
||||||
|
if config.verbose {
|
||||||
|
io::stdout().write_str(fmt!("push (%s) %s %s %s",
|
||||||
|
config.target, args.prog,
|
||||||
|
copy_result.out, copy_result.err));
|
||||||
|
}
|
||||||
|
|
||||||
|
logv(config, fmt!("executing (%s) %s", config.target, cmdline));
|
||||||
|
|
||||||
|
let mut runargs = ~[];
|
||||||
|
|
||||||
|
// run test via adb_run_wrapper
|
||||||
|
runargs.push(~"shell");
|
||||||
|
runargs.push(fmt!("%s/adb_run_wrapper.sh", config.adb_test_dir));
|
||||||
|
runargs.push(fmt!("%s", config.adb_test_dir));
|
||||||
|
runargs.push(fmt!("%s", prog_short));
|
||||||
|
|
||||||
|
for args.args.iter().advance |tv| {
|
||||||
|
runargs.push(tv.to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
|
||||||
|
|
||||||
|
// get exitcode of result
|
||||||
|
runargs = ~[];
|
||||||
|
runargs.push(~"shell");
|
||||||
|
runargs.push(~"cat");
|
||||||
|
runargs.push(fmt!("%s/%s.exitcode", config.adb_test_dir, prog_short));
|
||||||
|
|
||||||
|
let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
|
||||||
|
procsrv::run("", config.adb_path, runargs, ~[(~"",~"")],
|
||||||
|
Some(~""));
|
||||||
|
|
||||||
|
let mut exitcode : int = 0;
|
||||||
|
for exitcode_out.iter().advance |c| {
|
||||||
|
if !c.is_digit() { break; }
|
||||||
|
exitcode = exitcode * 10 + match c {
|
||||||
|
'0' .. '9' => c as int - ('0' as int),
|
||||||
|
_ => 101,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get stdout of result
|
||||||
|
runargs = ~[];
|
||||||
|
runargs.push(~"shell");
|
||||||
|
runargs.push(~"cat");
|
||||||
|
runargs.push(fmt!("%s/%s.stdout", config.adb_test_dir, prog_short));
|
||||||
|
|
||||||
|
let procsrv::Result{ out: stdout_out, err: _, status: _ } =
|
||||||
|
procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
|
||||||
|
|
||||||
|
// get stderr of result
|
||||||
|
runargs = ~[];
|
||||||
|
runargs.push(~"shell");
|
||||||
|
runargs.push(~"cat");
|
||||||
|
runargs.push(fmt!("%s/%s.stderr", config.adb_test_dir, prog_short));
|
||||||
|
|
||||||
|
let procsrv::Result{ out: stderr_out, err: _, status: _ } =
|
||||||
|
procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
|
||||||
|
|
||||||
|
dump_output(config, testfile, stdout_out, stderr_out);
|
||||||
|
|
||||||
|
ProcRes {status: exitcode, stdout: stdout_out, stderr: stderr_out, cmdline: cmdline }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _dummy_exec_compiled_test(config: &config, props: &TestProps,
|
||||||
|
testfile: &Path) -> ProcRes {
|
||||||
|
|
||||||
|
let args = make_run_args(config, props, testfile);
|
||||||
|
let cmdline = make_cmdline("", args.prog, args.args);
|
||||||
|
|
||||||
|
match config.mode {
|
||||||
|
mode_run_fail => ProcRes {status: 101, stdout: ~"",
|
||||||
|
stderr: ~"", cmdline: cmdline},
|
||||||
|
_ => ProcRes {status: 0, stdout: ~"",
|
||||||
|
stderr: ~"", cmdline: cmdline}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
|
||||||
|
let tstr = aux_output_dir_name(config, testfile).to_str();
|
||||||
|
|
||||||
|
let dirs = os::list_dir_path(&Path(tstr));
|
||||||
|
for dirs.iter().advance |file| {
|
||||||
|
|
||||||
|
if (file.filetype() == Some(~".so")) {
|
||||||
|
|
||||||
|
let copy_result = procsrv::run("", config.adb_path,
|
||||||
|
[~"push", file.to_str(), copy config.adb_test_dir],
|
||||||
|
~[(~"",~"")], Some(~""));
|
||||||
|
|
||||||
|
if config.verbose {
|
||||||
|
io::stdout().write_str(fmt!("push (%s) %s %s %s",
|
||||||
|
config.target, file.to_str(),
|
||||||
|
copy_result.out, copy_result.err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ use common::config;
|
|||||||
use core::io;
|
use core::io;
|
||||||
use core::os::getenv;
|
use core::os::getenv;
|
||||||
|
|
||||||
pub fn make_new_path(path: ~str) -> ~str {
|
pub fn make_new_path(path: &str) -> ~str {
|
||||||
|
|
||||||
// Windows just uses PATH as the library search path, so we have to
|
// Windows just uses PATH as the library search path, so we have to
|
||||||
// maintain the current value while adding our own
|
// maintain the current value while adding our own
|
||||||
@ -23,7 +23,7 @@ pub fn make_new_path(path: ~str) -> ~str {
|
|||||||
Some(curr) => {
|
Some(curr) => {
|
||||||
fmt!("%s%s%s", path, path_div(), curr)
|
fmt!("%s%s%s", path, path_div(), curr)
|
||||||
}
|
}
|
||||||
None => path
|
None => path.to_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ pub fn path_div() -> ~str { ~":" }
|
|||||||
#[cfg(target_os = "win32")]
|
#[cfg(target_os = "win32")]
|
||||||
pub fn path_div() -> ~str { ~";" }
|
pub fn path_div() -> ~str { ~";" }
|
||||||
|
|
||||||
pub fn logv(config: config, s: ~str) {
|
pub fn logv(config: &config, s: ~str) {
|
||||||
debug!("%s", s);
|
debug!("%s", s);
|
||||||
if config.verbose { io::println(s); }
|
if config.verbose { io::println(s); }
|
||||||
}
|
}
|
||||||
|
@ -9,24 +9,23 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#[no_core];
|
#[no_core];
|
||||||
extern mod core(vers = "0.6");
|
#[no_std];
|
||||||
|
|
||||||
|
extern mod core(name = "std", vers = "0.7");
|
||||||
|
|
||||||
#[cfg(rustpkg)]
|
#[cfg(rustpkg)]
|
||||||
extern mod this(name = "rustpkg", vers = "0.6");
|
extern mod this(name = "rustpkg");
|
||||||
|
|
||||||
#[cfg(fuzzer)]
|
|
||||||
extern mod this(name = "fuzzer", vers = "0.6");
|
|
||||||
|
|
||||||
#[cfg(rustdoc)]
|
#[cfg(rustdoc)]
|
||||||
extern mod this(name = "rustdoc", vers = "0.6");
|
extern mod this(name = "rustdoc");
|
||||||
|
|
||||||
#[cfg(rusti)]
|
#[cfg(rusti)]
|
||||||
extern mod this(name = "rusti", vers = "0.6");
|
extern mod this(name = "rusti");
|
||||||
|
|
||||||
#[cfg(rust)]
|
#[cfg(rust)]
|
||||||
extern mod this(name = "rust", vers = "0.6");
|
extern mod this(name = "rust");
|
||||||
|
|
||||||
#[cfg(rustc)]
|
#[cfg(rustc)]
|
||||||
extern mod this(name = "rustc", vers = "0.6");
|
extern mod this(name = "rustc");
|
||||||
|
|
||||||
fn main() { this::main() }
|
fn main() { this::main() }
|
||||||
|
36
src/etc/adb_run_wrapper.sh
Executable file
36
src/etc/adb_run_wrapper.sh
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#
|
||||||
|
# usage : adb_run_wrapper [test dir - where test executables exist] [test executable]
|
||||||
|
#
|
||||||
|
|
||||||
|
# Sometimes android shell produce exitcode "1 : Text File Busy"
|
||||||
|
# Retry after $WAIT seconds, expecting resource cleaned-up
|
||||||
|
WAIT=10
|
||||||
|
PATH=$1
|
||||||
|
if [ -d "$PATH" ]
|
||||||
|
then
|
||||||
|
shift
|
||||||
|
RUN=$1
|
||||||
|
|
||||||
|
if [ ! -z "$RUN" ]
|
||||||
|
then
|
||||||
|
shift
|
||||||
|
|
||||||
|
L_RET=1
|
||||||
|
L_COUNT=0
|
||||||
|
cd $PATH
|
||||||
|
while [ $L_RET -eq 1 ]
|
||||||
|
do
|
||||||
|
TEST_EXEC_ENV=22 LD_LIBRARY_PATH=$PATH $PATH/$RUN $@ 1>$PATH/$RUN.stdout 2>$PATH/$RUN.stderr
|
||||||
|
L_RET=$?
|
||||||
|
if [ $L_COUNT -gt 0 ]
|
||||||
|
then
|
||||||
|
/system/bin/sleep $WAIT
|
||||||
|
/system/bin/sync
|
||||||
|
fi
|
||||||
|
L_COUNT=$((L_COUNT+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo $L_RET > $PATH/$RUN.exitcode
|
||||||
|
|
||||||
|
fi
|
||||||
|
fi
|
@ -9,7 +9,7 @@ my $anchors = {};
|
|||||||
my $i = 0;
|
my $i = 0;
|
||||||
foreach $line (@lines) {
|
foreach $line (@lines) {
|
||||||
$i++;
|
$i++;
|
||||||
if ($line =~ m/id="([^"]+)"/) {
|
if ($line =~ m/id="([^"]+)"/) {
|
||||||
$anchors->{$1} = $i;
|
$anchors->{$1} = $i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,10 +17,9 @@ foreach $line (@lines) {
|
|||||||
$i = 0;
|
$i = 0;
|
||||||
foreach $line (@lines) {
|
foreach $line (@lines) {
|
||||||
$i++;
|
$i++;
|
||||||
while ($line =~ m/href="#([^"]+)"/g) {
|
while ($line =~ m/href="#([^"]+)"/g) {
|
||||||
if (! exists($anchors->{$1})) {
|
if (! exists($anchors->{$1})) {
|
||||||
print "$file:$i: $1 referenced\n";
|
print "$file:$i: $1 referenced\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,17 +49,18 @@ c.close()
|
|||||||
|
|
||||||
d = open("tmp/run_pass_stage2_driver.rs", "w")
|
d = open("tmp/run_pass_stage2_driver.rs", "w")
|
||||||
d.write("// AUTO-GENERATED FILE: DO NOT EDIT\n")
|
d.write("// AUTO-GENERATED FILE: DO NOT EDIT\n")
|
||||||
d.write("extern mod std;\n")
|
d.write("extern mod extra;\n")
|
||||||
d.write("extern mod run_pass_stage2;\n")
|
d.write("extern mod run_pass_stage2;\n")
|
||||||
d.write("use run_pass_stage2::*;\n")
|
d.write("use run_pass_stage2::*;\n")
|
||||||
d.write("use core::io::WriterUtil;\n");
|
d.write("use std::io::WriterUtil;\n");
|
||||||
|
d.write("use std::io;\n");
|
||||||
d.write("fn main() {\n");
|
d.write("fn main() {\n");
|
||||||
d.write(" let out = io::stdout();\n");
|
d.write(" let out = io::stdout();\n");
|
||||||
i = 0
|
i = 0
|
||||||
for t in stage2_tests:
|
for t in stage2_tests:
|
||||||
p = os.path.join("test", "run-pass", t)
|
p = os.path.join("test", "run-pass", t)
|
||||||
p = p.replace("\\", "\\\\")
|
p = p.replace("\\", "\\\\")
|
||||||
d.write(" out.write_str(~\"run-pass [stage2]: %s\\n\");\n" % p)
|
d.write(" out.write_str(\"run-pass [stage2]: %s\\n\");\n" % p)
|
||||||
d.write(" t_%d::main();\n" % i)
|
d.write(" t_%d::main();\n" % i)
|
||||||
i += 1
|
i += 1
|
||||||
d.write("}\n")
|
d.write("}\n")
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
--regex-rust=/[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
|
--regex-rust=/[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
|
||||||
--regex-rust=/[ \t]*enum[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
|
--regex-rust=/[ \t]*enum[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
|
||||||
--regex-rust=/[ \t]*struct[ \t]+([a-zA-Z0-9_]+)/\1/m,types/
|
--regex-rust=/[ \t]*struct[ \t]+([a-zA-Z0-9_]+)/\1/m,types/
|
||||||
--regex-rust=/[ \t]*class[ \t]+([a-zA-Z0-9_]+)/\1/m,types/
|
|
||||||
--regex-rust=/[ \t]*mod[ \t]+([a-zA-Z0-9_]+)/\1/m,modules/
|
--regex-rust=/[ \t]*mod[ \t]+([a-zA-Z0-9_]+)/\1/m,modules/
|
||||||
--regex-rust=/[ \t]*const[ \t]+([a-zA-Z0-9_]+)/\1/m,consts/
|
--regex-rust=/[ \t]*static[ \t]+([a-zA-Z0-9_]+)/\1/m,consts/
|
||||||
--regex-rust=/[ \t]*trait[ \t]+([a-zA-Z0-9_]+)/\1/m,traits/
|
--regex-rust=/[ \t]*trait[ \t]+([a-zA-Z0-9_]+)/\1/m,traits/
|
||||||
--regex-rust=/[ \t]*impl[ \t]+([a-zA-Z0-9_]+)/\1/m,impls/
|
--regex-rust=/[ \t]*impl[ \t]+([a-zA-Z0-9_]+)/\1/m,impls/
|
||||||
--regex-rust=/[ \t]*impl[ \t]+of[ \t]([a-zA-Z0-9_]+)/\1/m,impls/
|
--regex-rust=/[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/m,macros/
|
||||||
|
@ -23,7 +23,12 @@
|
|||||||
:require 'rust-mode
|
:require 'rust-mode
|
||||||
:group 'rust-mode)
|
:group 'rust-mode)
|
||||||
|
|
||||||
(defvar rust-indent-unit 4)
|
(defcustom rust-indent-unit 4
|
||||||
|
"Amount of offset per level of indentation"
|
||||||
|
:type 'integer
|
||||||
|
:require 'rust-mode
|
||||||
|
:group 'rust-mode)
|
||||||
|
|
||||||
(defvar rust-syntax-table (let ((table (make-syntax-table)))
|
(defvar rust-syntax-table (let ((table (make-syntax-table)))
|
||||||
(c-populate-syntax-table table)
|
(c-populate-syntax-table table)
|
||||||
table))
|
table))
|
||||||
|
@ -57,10 +57,9 @@ while cur < len(lines):
|
|||||||
if not ignore:
|
if not ignore:
|
||||||
if not re.search(r"\bfn main\b", block):
|
if not re.search(r"\bfn main\b", block):
|
||||||
block = "fn main() {\n" + block + "\n}\n"
|
block = "fn main() {\n" + block + "\n}\n"
|
||||||
if not re.search(r"\bextern mod std\b", block):
|
if not re.search(r"\bextern mod extra\b", block):
|
||||||
block = "extern mod std;\n" + block
|
block = "extern mod extra;\n" + block
|
||||||
block = """#[ forbid(ctypes) ];
|
block = """#[ forbid(ctypes) ];
|
||||||
#[ forbid(deprecated_mode) ];
|
|
||||||
#[ forbid(deprecated_pattern) ];
|
#[ forbid(deprecated_pattern) ];
|
||||||
#[ forbid(implicit_copies) ];
|
#[ forbid(implicit_copies) ];
|
||||||
#[ forbid(non_implicitly_copyable_typarams) ];
|
#[ forbid(non_implicitly_copyable_typarams) ];
|
||||||
@ -68,12 +67,9 @@ while cur < len(lines):
|
|||||||
#[ forbid(type_limits) ];
|
#[ forbid(type_limits) ];
|
||||||
#[ forbid(unrecognized_lint) ];
|
#[ forbid(unrecognized_lint) ];
|
||||||
#[ forbid(unused_imports) ];
|
#[ forbid(unused_imports) ];
|
||||||
#[ forbid(vecs_implicitly_copyable) ];
|
|
||||||
#[ forbid(while_true) ];
|
#[ forbid(while_true) ];
|
||||||
|
|
||||||
#[ warn(deprecated_self) ];
|
#[ warn(non_camel_case_types) ];\n
|
||||||
#[ warn(non_camel_case_types) ];
|
|
||||||
#[ warn(structural_records) ];\n
|
|
||||||
""" + block
|
""" + block
|
||||||
if xfail:
|
if xfail:
|
||||||
block = "// xfail-test\n" + block
|
block = "// xfail-test\n" + block
|
||||||
|
@ -8,4 +8,3 @@ Instructions for Ubuntu Linux 12.04+
|
|||||||
2) Copy the included "share" folder into "~/.local/"
|
2) Copy the included "share" folder into "~/.local/"
|
||||||
|
|
||||||
3) Open a shell in "~/.local/share/" and run "update-mime-database mime"
|
3) Open a shell in "~/.local/share/" and run "update-mime-database mime"
|
||||||
|
|
||||||
|
@ -123,11 +123,11 @@
|
|||||||
<keyword>mode_t</keyword>
|
<keyword>mode_t</keyword>
|
||||||
<keyword>ssize_t</keyword>
|
<keyword>ssize_t</keyword>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context id="self" style-ref="identifier">
|
<context id="self" style-ref="identifier">
|
||||||
<keyword>self</keyword>
|
<keyword>self</keyword>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context id="constants" style-ref="constant">
|
<context id="constants" style-ref="constant">
|
||||||
<keyword>true</keyword>
|
<keyword>true</keyword>
|
||||||
<keyword>false</keyword>
|
<keyword>false</keyword>
|
||||||
@ -261,4 +261,3 @@
|
|||||||
</definitions>
|
</definitions>
|
||||||
|
|
||||||
</language>
|
</language>
|
||||||
|
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
<mime-type type="text/x-rust">
|
<mime-type type="text/x-rust">
|
||||||
<comment>Rust Source</comment>
|
<comment>Rust Source</comment>
|
||||||
<glob pattern="*.rs"/>
|
<glob pattern="*.rs"/>
|
||||||
<glob pattern="*.rc"/>
|
<glob pattern="*.rc"/>
|
||||||
</mime-type>
|
</mime-type>
|
||||||
</mime-info>
|
</mime-info>
|
||||||
|
@ -14,4 +14,3 @@ while (<>) {
|
|||||||
$indent -= 1;
|
$indent -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
|
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
|
||||||
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
|
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
|
||||||
]>
|
]>
|
||||||
<language name="Rust" version="0.6" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
|
<language name="Rust" version="0.7" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
|
||||||
<highlighting>
|
<highlighting>
|
||||||
<list name="fn">
|
<list name="fn">
|
||||||
<item> fn </item>
|
<item> fn </item>
|
||||||
@ -49,6 +49,7 @@
|
|||||||
<item> Copy </item>
|
<item> Copy </item>
|
||||||
<item> Send </item>
|
<item> Send </item>
|
||||||
<item> Owned </item>
|
<item> Owned </item>
|
||||||
|
<item> Sized </item>
|
||||||
<item> Eq </item>
|
<item> Eq </item>
|
||||||
<item> Ord </item>
|
<item> Ord </item>
|
||||||
<item> Num </item>
|
<item> Num </item>
|
||||||
@ -57,8 +58,8 @@
|
|||||||
<item> Add </item>
|
<item> Add </item>
|
||||||
<item> Sub </item>
|
<item> Sub </item>
|
||||||
<item> Mul </item>
|
<item> Mul </item>
|
||||||
<item> Div </item>
|
<item> Quot </item>
|
||||||
<item> Modulo </item>
|
<item> Rem </item>
|
||||||
<item> Neg </item>
|
<item> Neg </item>
|
||||||
<item> BitAnd </item>
|
<item> BitAnd </item>
|
||||||
<item> BitOr </item>
|
<item> BitOr </item>
|
||||||
|
@ -52,5 +52,3 @@ def download_new_file (date, rev, platform, hsh):
|
|||||||
for ff in newestSet["files"]:
|
for ff in newestSet["files"]:
|
||||||
download_new_file (newestSet["date"], newestSet["rev"],
|
download_new_file (newestSet["date"], newestSet["rev"],
|
||||||
ff["platform"], ff["hash"])
|
ff["platform"], ff["hash"])
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,4 +243,3 @@ int main() {
|
|||||||
extra_consts();
|
extra_consts();
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,4 +96,3 @@ def check_license(name, contents):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
Binary file not shown.
@ -1,13 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
TARG_DIR=$1
|
TARG_DIR=$1
|
||||||
PREFIX=$2
|
PREFIX=$2
|
||||||
|
|
||||||
BINDIR=bin
|
BINDIR=bin
|
||||||
LIBDIR=lib
|
LIBDIR=lib
|
||||||
|
|
||||||
OS=`uname -s`
|
OS=`uname -s`
|
||||||
case $OS in
|
case $OS in
|
||||||
("Linux"|"FreeBSD")
|
("Linux"|"FreeBSD")
|
||||||
BIN_SUF=
|
BIN_SUF=
|
||||||
LIB_SUF=.so
|
LIB_SUF=.so
|
||||||
|
@ -33,6 +33,3 @@ for line in f.readlines():
|
|||||||
print("got download with ok hash")
|
print("got download with ok hash")
|
||||||
else:
|
else:
|
||||||
raise Exception("bad hash on download")
|
raise Exception("bad hash on download")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,4 +77,3 @@ while (my ($key, $substs) = each %funcs) {
|
|||||||
}
|
}
|
||||||
print "\n";
|
print "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#define CFG_VERSION GetEnv("CFG_VERSION")
|
#define CFG_VERSION GetEnv("CFG_VERSION")
|
||||||
|
#define CFG_VERSION_WIN GetEnv("CFG_VERSION_WIN")
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ AppVersion={#CFG_VERSION}
|
|||||||
AppCopyright=Copyright (C) 2006-2013 Mozilla Foundation, MIT license
|
AppCopyright=Copyright (C) 2006-2013 Mozilla Foundation, MIT license
|
||||||
AppPublisher=Mozilla Foundation
|
AppPublisher=Mozilla Foundation
|
||||||
AppPublisherURL=http://www.rust-lang.org
|
AppPublisherURL=http://www.rust-lang.org
|
||||||
VersionInfoVersion={#CFG_VERSION}
|
VersionInfoVersion={#CFG_VERSION_WIN}
|
||||||
LicenseFile=LICENSE.txt
|
LicenseFile=LICENSE.txt
|
||||||
|
|
||||||
DisableWelcomePage=true
|
DisableWelcomePage=true
|
||||||
|
@ -26,29 +26,29 @@ download_unpack_base = os.path.join(download_dir_base, "unpack")
|
|||||||
|
|
||||||
snapshot_files = {
|
snapshot_files = {
|
||||||
"linux": ["bin/rustc",
|
"linux": ["bin/rustc",
|
||||||
"lib/libcore-*.so",
|
|
||||||
"lib/libstd-*.so",
|
"lib/libstd-*.so",
|
||||||
|
"lib/libextra-*.so",
|
||||||
"lib/librustc-*.so",
|
"lib/librustc-*.so",
|
||||||
"lib/libsyntax-*.so",
|
"lib/libsyntax-*.so",
|
||||||
"lib/librustrt.so",
|
"lib/librustrt.so",
|
||||||
"lib/librustllvm.so"],
|
"lib/librustllvm.so"],
|
||||||
"macos": ["bin/rustc",
|
"macos": ["bin/rustc",
|
||||||
"lib/libcore-*.dylib",
|
|
||||||
"lib/libstd-*.dylib",
|
"lib/libstd-*.dylib",
|
||||||
|
"lib/libextra-*.dylib",
|
||||||
"lib/librustc-*.dylib",
|
"lib/librustc-*.dylib",
|
||||||
"lib/libsyntax-*.dylib",
|
"lib/libsyntax-*.dylib",
|
||||||
"lib/librustrt.dylib",
|
"lib/librustrt.dylib",
|
||||||
"lib/librustllvm.dylib"],
|
"lib/librustllvm.dylib"],
|
||||||
"winnt": ["bin/rustc.exe",
|
"winnt": ["bin/rustc.exe",
|
||||||
"bin/core-*.dll",
|
|
||||||
"bin/std-*.dll",
|
"bin/std-*.dll",
|
||||||
|
"bin/extra-*.dll",
|
||||||
"bin/rustc-*.dll",
|
"bin/rustc-*.dll",
|
||||||
"bin/syntax-*.dll",
|
"bin/syntax-*.dll",
|
||||||
"bin/rustrt.dll",
|
"bin/rustrt.dll",
|
||||||
"bin/rustllvm.dll"],
|
"bin/rustllvm.dll"],
|
||||||
"freebsd": ["bin/rustc",
|
"freebsd": ["bin/rustc",
|
||||||
"lib/libcore-*.so",
|
|
||||||
"lib/libstd-*.so",
|
"lib/libstd-*.so",
|
||||||
|
"lib/libextra-*.so",
|
||||||
"lib/librustc-*.so",
|
"lib/librustc-*.so",
|
||||||
"lib/libsyntax-*.so",
|
"lib/libsyntax-*.so",
|
||||||
"lib/librustrt.so",
|
"lib/librustrt.so",
|
||||||
|
Binary file not shown.
@ -80,4 +80,3 @@ def sugarise_file(path):
|
|||||||
for (dirpath, dirnames, filenames) in os.walk('.'):
|
for (dirpath, dirnames, filenames) in os.walk('.'):
|
||||||
for name in fnmatch.filter(filenames, '*.r[sc]'):
|
for name in fnmatch.filter(filenames, '*.r[sc]'):
|
||||||
sugarise_file(os.path.join(dirpath, name))
|
sugarise_file(os.path.join(dirpath, name))
|
||||||
|
|
||||||
|
@ -81,4 +81,3 @@ except UnicodeDecodeError, e:
|
|||||||
|
|
||||||
|
|
||||||
sys.exit(err)
|
sys.exit(err)
|
||||||
|
|
||||||
|
@ -112,12 +112,54 @@ def escape_char(c):
|
|||||||
return "'\\u%4.4x'" % c
|
return "'\\u%4.4x'" % c
|
||||||
return "'\\U%8.8x'" % c
|
return "'\\U%8.8x'" % c
|
||||||
|
|
||||||
|
def ch_prefix(ix):
|
||||||
|
if ix == 0:
|
||||||
|
return " "
|
||||||
|
if ix % 2 == 0:
|
||||||
|
return ",\n "
|
||||||
|
else:
|
||||||
|
return ", "
|
||||||
|
|
||||||
|
def emit_bsearch_range_table(f):
|
||||||
|
f.write("""
|
||||||
|
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
|
||||||
|
use cmp::{Equal, Less, Greater};
|
||||||
|
use vec::ImmutableVector;
|
||||||
|
use option::None;
|
||||||
|
(do r.bsearch |&(lo,hi)| {
|
||||||
|
if lo <= c && c <= hi { Equal }
|
||||||
|
else if hi < c { Less }
|
||||||
|
else { Greater }
|
||||||
|
}) != None
|
||||||
|
}\n\n
|
||||||
|
""");
|
||||||
|
|
||||||
def emit_property_module(f, mod, tbl):
|
def emit_property_module(f, mod, tbl):
|
||||||
|
f.write("pub mod %s {\n" % mod)
|
||||||
|
keys = tbl.keys()
|
||||||
|
keys.sort()
|
||||||
|
emit_bsearch_range_table(f);
|
||||||
|
for cat in keys:
|
||||||
|
f.write(" static %s_table : &'static [(char,char)] = &[\n" % cat)
|
||||||
|
ix = 0
|
||||||
|
for pair in tbl[cat]:
|
||||||
|
f.write(ch_prefix(ix))
|
||||||
|
f.write("(%s, %s)" % (escape_char(pair[0]), escape_char(pair[1])))
|
||||||
|
ix += 1
|
||||||
|
f.write("\n ];\n\n")
|
||||||
|
|
||||||
|
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||||
|
f.write(" bsearch_range_table(c, %s_table)\n" % cat)
|
||||||
|
f.write(" }\n\n")
|
||||||
|
f.write("}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def emit_property_module_old(f, mod, tbl):
|
||||||
f.write("mod %s {\n" % mod)
|
f.write("mod %s {\n" % mod)
|
||||||
keys = tbl.keys()
|
keys = tbl.keys()
|
||||||
keys.sort()
|
keys.sort()
|
||||||
for cat in keys:
|
for cat in keys:
|
||||||
f.write(" pure fn %s(c: char) -> bool {\n" % cat)
|
f.write(" fn %s(c: char) -> bool {\n" % cat)
|
||||||
f.write(" ret alt c {\n")
|
f.write(" ret alt c {\n")
|
||||||
prefix = ' '
|
prefix = ' '
|
||||||
for pair in tbl[cat]:
|
for pair in tbl[cat]:
|
||||||
@ -193,8 +235,27 @@ for i in [r]:
|
|||||||
rf = open(r, "w")
|
rf = open(r, "w")
|
||||||
|
|
||||||
(canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt")
|
(canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt")
|
||||||
emit_decomp_module(rf, canon_decomp, compat_decomp)
|
|
||||||
|
# Preamble
|
||||||
|
rf.write('''// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// The following code was generated by "src/etc/unicode.py"
|
||||||
|
|
||||||
|
#[allow(missing_doc)];
|
||||||
|
|
||||||
|
''')
|
||||||
|
|
||||||
emit_property_module(rf, "general_category", gencats)
|
emit_property_module(rf, "general_category", gencats)
|
||||||
|
|
||||||
|
#emit_decomp_module(rf, canon_decomp, compat_decomp)
|
||||||
|
|
||||||
derived = load_derived_core_properties("DerivedCoreProperties.txt")
|
derived = load_derived_core_properties("DerivedCoreProperties.txt")
|
||||||
emit_property_module(rf, "derived_property", derived)
|
emit_property_module(rf, "derived_property", derived)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
"Highlight the 100th text column
|
|
||||||
"Feature became available in v7.3
|
|
||||||
if version >= 703
|
|
||||||
set colorcolumn=100
|
|
||||||
endif
|
|
@ -1,4 +1,4 @@
|
|||||||
if exists('g:no_rust_conceal') || !has('conceal') || &enc != 'utf-8'
|
if !exists('g:rust_conceal') || !has('conceal') || &enc != 'utf-8'
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -11,10 +11,6 @@ syn match rustRightArrowHead contained ">" conceal cchar=
|
|||||||
syn match rustRightArrowTail contained "-" conceal cchar=⟶
|
syn match rustRightArrowTail contained "-" conceal cchar=⟶
|
||||||
syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail
|
syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail
|
||||||
|
|
||||||
syn match rustLeftRightArrowHead contained ">" conceal cchar=
|
|
||||||
syn match rustLeftRightArrowTail contained "<-" conceal cchar=⟷
|
|
||||||
syn match rustNiceOperator "<->" contains=rustLeftRightArrowHead,rustLeftRightArrowTail
|
|
||||||
|
|
||||||
syn match rustFatRightArrowHead contained ">" conceal cchar=
|
syn match rustFatRightArrowHead contained ">" conceal cchar=
|
||||||
syn match rustFatRightArrowTail contained "=" conceal cchar=⟹
|
syn match rustFatRightArrowTail contained "=" conceal cchar=⟹
|
||||||
syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail
|
syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail
|
||||||
|
@ -5,4 +5,7 @@ if exists("b:did_indent")
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
let b:did_indent = 1
|
let b:did_indent = 1
|
||||||
setlocal smartindent
|
|
||||||
|
setlocal cindent
|
||||||
|
setlocal cinoptions=L0,(0,Ws,JN
|
||||||
|
setlocal cinkeys=0{,0},!^F,o,O
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
" Language: Rust
|
" Language: Rust
|
||||||
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
|
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
|
||||||
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
|
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
|
||||||
" Last Change: 2012 Dec 25
|
" Last Change: 2013 Jun 14
|
||||||
|
|
||||||
if version < 600
|
if version < 600
|
||||||
syntax clear
|
syntax clear
|
||||||
@ -13,13 +13,16 @@ endif
|
|||||||
syn keyword rustConditional match if else
|
syn keyword rustConditional match if else
|
||||||
syn keyword rustOperator as
|
syn keyword rustOperator as
|
||||||
|
|
||||||
syn keyword rustKeyword break copy do drop extern
|
syn match rustAssert "\<assert\(\w\)*!"
|
||||||
|
syn match rustFail "\<fail\(\w\)*!"
|
||||||
|
syn keyword rustKeyword break copy do extern
|
||||||
syn keyword rustKeyword for if impl let log
|
syn keyword rustKeyword for if impl let log
|
||||||
syn keyword rustKeyword copy do drop extern
|
syn keyword rustKeyword copy do extern
|
||||||
syn keyword rustKeyword for impl let log
|
syn keyword rustKeyword for impl let log
|
||||||
syn keyword rustKeyword loop mod once priv pub
|
syn keyword rustKeyword loop mod once priv pub
|
||||||
syn keyword rustKeyword return
|
syn keyword rustKeyword return
|
||||||
syn keyword rustKeyword unsafe use while
|
syn keyword rustKeyword unsafe while
|
||||||
|
syn keyword rustKeyword use nextgroup=rustModPath skipwhite
|
||||||
" FIXME: Scoped impl's name is also fallen in this category
|
" FIXME: Scoped impl's name is also fallen in this category
|
||||||
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite
|
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite
|
||||||
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
|
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
|
||||||
@ -28,8 +31,8 @@ syn keyword rustStorage const mut ref static
|
|||||||
syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
||||||
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
|
||||||
|
|
||||||
" Reserved words
|
" reserved
|
||||||
syn keyword rustKeyword m32 m64 m128 f80 f16 f128 be
|
syn keyword rustKeyword be
|
||||||
|
|
||||||
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
|
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
|
||||||
syn keyword rustType f64 i8 i16 i32 i64 str Self
|
syn keyword rustType f64 i8 i16 i32 i64 str Self
|
||||||
@ -44,9 +47,10 @@ syn keyword rustType size_t ptrdiff_t clock_t time_t
|
|||||||
syn keyword rustType c_longlong c_ulonglong intptr_t uintptr_t
|
syn keyword rustType c_longlong c_ulonglong intptr_t uintptr_t
|
||||||
syn keyword rustType off_t dev_t ino_t pid_t mode_t ssize_t
|
syn keyword rustType off_t dev_t ino_t pid_t mode_t ssize_t
|
||||||
|
|
||||||
syn keyword rustTrait Const Copy Send Owned " inherent traits
|
syn keyword rustTrait Const Copy Send Owned Sized " inherent traits
|
||||||
syn keyword rustTrait Eq Ord Num Ptr
|
syn keyword rustTrait Clone Decodable Encodable IterBytes Rand ToStr
|
||||||
syn keyword rustTrait Drop Add Sub Mul Div Modulo Neg BitAnd BitOr
|
syn keyword rustTrait Eq Ord TotalEq TotalOrd Num Ptr
|
||||||
|
syn keyword rustTrait Drop Add Sub Mul Quot Rem Neg BitAnd BitOr
|
||||||
syn keyword rustTrait BitXor Shl Shr Index
|
syn keyword rustTrait BitXor Shl Shr Index
|
||||||
|
|
||||||
syn keyword rustSelf self
|
syn keyword rustSelf self
|
||||||
@ -72,19 +76,21 @@ syn keyword rustConstant STDIN_FILENO STDOUT_FILENO STDERR_FILENO
|
|||||||
" If foo::bar changes to foo.bar, change this ("::" to "\.").
|
" If foo::bar changes to foo.bar, change this ("::" to "\.").
|
||||||
" If foo::bar changes to Foo::bar, change this (first "\w" to "\u").
|
" If foo::bar changes to Foo::bar, change this (first "\w" to "\u").
|
||||||
syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3
|
syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3
|
||||||
|
syn match rustModPath "\w\(\w\)*" contained " only for 'use path;'
|
||||||
syn match rustModPathSep "::"
|
syn match rustModPathSep "::"
|
||||||
|
|
||||||
syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1
|
syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1
|
||||||
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
|
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
|
||||||
|
|
||||||
syn match rustMacro '\w\(\w\)*!'
|
syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail
|
||||||
syn match rustMacro '#\w\(\w\)*'
|
syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustFail
|
||||||
|
|
||||||
syn match rustFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlLjzt]\|ll\|hh\)\=\([aAbdiuoxXDOUfFeEgGcCsSpn?]\|\[\^\=.[^]]*\]\)" contained
|
syn match rustFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlLjzt]\|ll\|hh\)\=\([aAbdiuoxXDOUfFeEgGcCsSpn?]\|\[\^\=.[^]]*\]\)" contained
|
||||||
syn match rustFormat display "%%" contained
|
syn match rustFormat display "%%" contained
|
||||||
syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat
|
syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat
|
||||||
|
|
||||||
syn region rustAttribute start="#\[" end="\]" contains=rustString
|
syn region rustAttribute start="#\[" end="\]" contains=rustString,rustDeriving
|
||||||
|
syn region rustDeriving start="deriving(" end=")" contains=rustTrait
|
||||||
|
|
||||||
" Number literals
|
" Number literals
|
||||||
syn match rustNumber display "\<[0-9][0-9_]*\>"
|
syn match rustNumber display "\<[0-9][0-9_]*\>"
|
||||||
@ -110,8 +116,11 @@ syn match rustFloat display "\<[0-9][0-9_]*\.[0-9_]\+\%([eE][+-]\=[0-9
|
|||||||
syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*"
|
syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*"
|
||||||
syn match rustCharacter "'\([^'\\]\|\\\(['nrt\\\"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'"
|
syn match rustCharacter "'\([^'\\]\|\\\(['nrt\\\"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'"
|
||||||
|
|
||||||
syn region rustComment start="/\*" end="\*/" contains=rustComment,rustTodo
|
syn region rustCommentDoc start="/\*[\*!]" end="\*/"
|
||||||
syn region rustComment start="//" skip="\\$" end="$" contains=rustTodo keepend
|
syn region rustCommentDoc start="//[/!]" skip="\\$" end="$" keepend
|
||||||
|
syn match rustComment "/\*\*/"
|
||||||
|
syn region rustComment start="/\*\([^\*!]\|$\)" end="\*/" contains=rustTodo
|
||||||
|
syn region rustComment start="//\([^/!]\|$\)" skip="\\$" end="$" contains=rustTodo keepend
|
||||||
|
|
||||||
syn keyword rustTodo contained TODO FIXME XXX NB
|
syn keyword rustTodo contained TODO FIXME XXX NB
|
||||||
|
|
||||||
@ -134,16 +143,24 @@ hi def link rustConditional Conditional
|
|||||||
hi def link rustIdentifier Identifier
|
hi def link rustIdentifier Identifier
|
||||||
hi def link rustModPath Include
|
hi def link rustModPath Include
|
||||||
hi def link rustFuncName Function
|
hi def link rustFuncName Function
|
||||||
|
hi def link rustFuncCall Function
|
||||||
|
hi def link rustCommentDoc SpecialComment
|
||||||
hi def link rustComment Comment
|
hi def link rustComment Comment
|
||||||
hi def link rustMacro Macro
|
hi def link rustMacro Macro
|
||||||
hi def link rustType Type
|
hi def link rustType Type
|
||||||
hi def link rustTodo Todo
|
hi def link rustTodo Todo
|
||||||
hi def link rustAttribute PreProc
|
hi def link rustAttribute PreProc
|
||||||
|
hi def link rustDeriving PreProc
|
||||||
hi def link rustStorage StorageClass
|
hi def link rustStorage StorageClass
|
||||||
hi def link rustLifetime Special
|
hi def link rustLifetime Special
|
||||||
|
|
||||||
" Other Suggestions:
|
" Other Suggestions:
|
||||||
|
" hi rustAttribute ctermfg=cyan
|
||||||
|
" hi rustDeriving ctermfg=cyan
|
||||||
|
" hi rustAssert ctermfg=yellow
|
||||||
|
" hi rustFail ctermfg=red
|
||||||
" hi rustMacro ctermfg=magenta
|
" hi rustMacro ctermfg=magenta
|
||||||
|
" hi rustModPathSep ctermfg=grey
|
||||||
|
|
||||||
syn sync minlines=200
|
syn sync minlines=200
|
||||||
syn sync maxlines=500
|
syn sync maxlines=500
|
||||||
|
@ -367,76 +367,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
enum-instruction-scheduling-1
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*fold_mod*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-2
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*fold_nmod*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-3
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*fold_crate*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-4
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*fold_enum*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-5
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*write_variant*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-6
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*merge_method_attrs*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-7
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*parse_config_*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-8
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*should_set_output_format_to_markdown_if_requested*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-9
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*get_authority*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
enum-instruction-scheduling-10
|
|
||||||
Memcheck:Cond
|
|
||||||
fun:*config_from_opts*
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
llvm-user-new-leak
|
llvm-user-new-leak
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
fun:_Znwj
|
fun:_Znwj
|
||||||
@ -471,7 +401,7 @@
|
|||||||
Helgrind:Race
|
Helgrind:Race
|
||||||
fun:_ZN15lock_and_signal27lock_held_by_current_threadEv
|
fun:_ZN15lock_and_signal27lock_held_by_current_threadEv
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
lock_and_signal-probably-threadsafe-access-outside-of-lock2
|
lock_and_signal-probably-threadsafe-access-outside-of-lock2
|
||||||
@ -565,3 +495,10 @@
|
|||||||
fun:__gxx_personality_v0
|
fun:__gxx_personality_v0
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
goddammit-llvm-why-u-no-valgrind
|
||||||
|
Memcheck:Cond
|
||||||
|
fun:*
|
||||||
|
...
|
||||||
|
}
|
||||||
|
121
src/etc/ziggurat_tables.py
Executable file
121
src/etc/ziggurat_tables.py
Executable file
@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# xfail-license
|
||||||
|
|
||||||
|
# This creates the tables used for distributions implemented using the
|
||||||
|
# ziggurat algorithm in `core::rand::distributions;`. They are
|
||||||
|
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
|
||||||
|
# They are changed rarely, so the generated file should be checked in
|
||||||
|
# to git.
|
||||||
|
#
|
||||||
|
# It creates 3 tables: X as in the paper, F which is f(x_i), and
|
||||||
|
# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached
|
||||||
|
# values which is not done in that paper (but is done in other
|
||||||
|
# variants). Note that the adZigR table is unnecessary because of
|
||||||
|
# algebra.
|
||||||
|
#
|
||||||
|
# It is designed to be compatible with Python 2 and 3.
|
||||||
|
|
||||||
|
from math import exp, sqrt, log, floor
|
||||||
|
import random
|
||||||
|
|
||||||
|
# The order should match the return value of `tables`
|
||||||
|
TABLE_NAMES = ['X', 'F', 'F_DIFF']
|
||||||
|
|
||||||
|
# The actual length of the table is 1 more, to stop
|
||||||
|
# index-out-of-bounds errors. This should match the bitwise operation
|
||||||
|
# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and
|
||||||
|
# *_V constants below depend on this value.
|
||||||
|
TABLE_LEN = 256
|
||||||
|
|
||||||
|
# equivalent to `zigNorInit` in Doornik2005, but generalised to any
|
||||||
|
# distribution. r = dR, v = dV, f = probability density function,
|
||||||
|
# f_inv = inverse of f
|
||||||
|
def tables(r, v, f, f_inv):
|
||||||
|
# compute the x_i
|
||||||
|
xvec = [0]*(TABLE_LEN+1)
|
||||||
|
|
||||||
|
xvec[0] = v / f(r)
|
||||||
|
xvec[1] = r
|
||||||
|
|
||||||
|
for i in range(2, TABLE_LEN):
|
||||||
|
last = xvec[i-1]
|
||||||
|
xvec[i] = f_inv(v / last + f(last))
|
||||||
|
|
||||||
|
# cache the f's
|
||||||
|
fvec = [0]*(TABLE_LEN+1)
|
||||||
|
fdiff = [0]*(TABLE_LEN+1)
|
||||||
|
for i in range(TABLE_LEN+1):
|
||||||
|
fvec[i] = f(xvec[i])
|
||||||
|
if i > 0:
|
||||||
|
fdiff[i] = fvec[i] - fvec[i-1]
|
||||||
|
|
||||||
|
return xvec, fvec, fdiff
|
||||||
|
|
||||||
|
# Distributions
|
||||||
|
# N(0, 1)
|
||||||
|
def norm_f(x):
|
||||||
|
return exp(-x*x/2.0)
|
||||||
|
def norm_f_inv(y):
|
||||||
|
return sqrt(-2.0*log(y))
|
||||||
|
|
||||||
|
NORM_R = 3.6541528853610088
|
||||||
|
NORM_V = 0.00492867323399
|
||||||
|
|
||||||
|
NORM = tables(NORM_R, NORM_V,
|
||||||
|
norm_f, norm_f_inv)
|
||||||
|
|
||||||
|
# Exp(1)
|
||||||
|
def exp_f(x):
|
||||||
|
return exp(-x)
|
||||||
|
def exp_f_inv(y):
|
||||||
|
return -log(y)
|
||||||
|
|
||||||
|
EXP_R = 7.69711747013104972
|
||||||
|
EXP_V = 0.0039496598225815571993
|
||||||
|
|
||||||
|
EXP = tables(EXP_R, EXP_V,
|
||||||
|
exp_f, exp_f_inv)
|
||||||
|
|
||||||
|
|
||||||
|
# Output the tables/constants/types
|
||||||
|
|
||||||
|
def render_static(name, type, value):
|
||||||
|
# no space or
|
||||||
|
return 'pub static %s: %s =%s;\n' % (name, type, value)
|
||||||
|
|
||||||
|
# static `name`: [`type`, .. `len(values)`] =
|
||||||
|
# [values[0], ..., values[3],
|
||||||
|
# values[4], ..., values[7],
|
||||||
|
# ... ];
|
||||||
|
def render_table(name, values):
|
||||||
|
rows = []
|
||||||
|
# 4 values on each row
|
||||||
|
for i in range(0, len(values), 4):
|
||||||
|
row = values[i:i+4]
|
||||||
|
rows.append(', '.join('%.18f' % f for f in row))
|
||||||
|
|
||||||
|
rendered = '\n [%s]' % ',\n '.join(rows)
|
||||||
|
return render_static(name, '[f64, .. %d]' % len(values), rendered)
|
||||||
|
|
||||||
|
|
||||||
|
with open('ziggurat_tables.rs', 'w') as f:
|
||||||
|
f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Tables for distributions which are sampled using the ziggurat
|
||||||
|
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||||
|
|
||||||
|
pub type ZigTable = &\'static [f64, .. %d];
|
||||||
|
''' % (TABLE_LEN + 1))
|
||||||
|
for name, tables, r in [('NORM', NORM, NORM_R),
|
||||||
|
('EXP', EXP, EXP_R)]:
|
||||||
|
f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r))
|
||||||
|
for (tabname, table) in zip(TABLE_NAMES, tables):
|
||||||
|
f.write(render_table('ZIG_%s_%s' % (name, tabname), table))
|
103
src/etc/zsh/_rust
Normal file
103
src/etc/zsh/_rust
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#compdef rustc
|
||||||
|
|
||||||
|
local -a _rustc_opts_switches _rustc_opts_lint _rustc_opts_debug
|
||||||
|
|
||||||
|
typeset -A opt_args
|
||||||
|
|
||||||
|
_rustc_opts_switches=(
|
||||||
|
--bin'[Compile an executable crate (default)]'
|
||||||
|
-c'[Compile and assemble, but do not link]'
|
||||||
|
--cfg'[Configure the compilation environment]'
|
||||||
|
--emit-llvm'[Produce an LLVM bitcode file]'
|
||||||
|
{-h,--help}'[Display this message]'
|
||||||
|
-L'[Add a directory to the library search path]'
|
||||||
|
--lib'[Compile a library crate]'
|
||||||
|
--linker'[Program to use for linking instead of the default.]'
|
||||||
|
--link-args'[FLAGS is a space-separated list of flags passed to the linker]'
|
||||||
|
--ls'[List the symbols defined by a library crate]'
|
||||||
|
--no-trans'[Run all passes except translation; no output]'
|
||||||
|
-O'[Equivalent to --opt-level=2]'
|
||||||
|
-o'[Write output to <filename>]'
|
||||||
|
--opt-level'[Optimize with possible levels 0-3]'
|
||||||
|
--out-dir'[Write output to compiler-chosen filename in <dir>]'
|
||||||
|
--parse-only'[Parse only; do not compile, assemble, or link]'
|
||||||
|
--pretty'[Pretty-print the input instead of compiling]'
|
||||||
|
-S'[Compile only; do not assemble or link]'
|
||||||
|
--save-temps'[Write intermediate files (.bc, .opt.bc, .o) in addition to normal output]'
|
||||||
|
--sysroot'[Override the system root]'
|
||||||
|
--test'[Build a test harness]'
|
||||||
|
--target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]'
|
||||||
|
--target-feature'[Target specific attributes (llc -mattr=help for detail)]'
|
||||||
|
--android-cross-path'[The path to the Android NDK]'
|
||||||
|
{-v,--version}'[Print version info and exit]'
|
||||||
|
)
|
||||||
|
_rustc_opts_lint=(
|
||||||
|
'path-statement[path statements with no effect]'
|
||||||
|
'deprecated-pattern[warn about deprecated uses of pattern bindings]'
|
||||||
|
'non-implicitly-copyable-typarams[passing non implicitly copyable types as copy type params]'
|
||||||
|
'missing-trait-doc[detects missing documentation for traits]'
|
||||||
|
'missing-struct-doc[detects missing documentation for structs]'
|
||||||
|
'ctypes[proper use of core::libc types in foreign modules]'
|
||||||
|
'implicit-copies[implicit copies of non implicitly copyable data]'
|
||||||
|
"unused-mut[detect mut variables which don't need to be mutable]"
|
||||||
|
'unused-imports[imports that are never used]'
|
||||||
|
'heap-memory[use of any (~ type or @ type) heap memory]'
|
||||||
|
'default-methods[allow default methods]'
|
||||||
|
'unused-variable[detect variables which are not used in any way]'
|
||||||
|
'dead-assignment[detect assignments that will never be read]'
|
||||||
|
'unrecognized-lint[unrecognized lint attribute]'
|
||||||
|
'type-limits[comparisons made useless by limits of the types involved]'
|
||||||
|
'unused-unsafe[unnecessary use of an `unsafe` block]'
|
||||||
|
'while-true[suggest using loop { } instead of while(true) { }]'
|
||||||
|
'non-camel-case-types[types, variants and traits should have camel case names]'
|
||||||
|
'managed-heap-memory[use of managed (@ type) heap memory]'
|
||||||
|
'unnecessary-allocation[detects unnecessary allocations that can be eliminated]'
|
||||||
|
'owned-heap-memory[use of owned (~ type) heap memory]'
|
||||||
|
)
|
||||||
|
|
||||||
|
_rustc_opts_debug=(
|
||||||
|
'verbose:in general, enable more debug printouts'
|
||||||
|
'time-passes:measure time of each rustc pass'
|
||||||
|
'count-llvm-insns:count where LLVM instrs originate'
|
||||||
|
'time-llvm-passes:measure time of each LLVM pass'
|
||||||
|
'trans-stats:gather trans statistics'
|
||||||
|
'asm-comments:generate comments into the assembly (may change behavior)'
|
||||||
|
'no-verify:skip LLVM verification'
|
||||||
|
'trace:emit trace logs'
|
||||||
|
'coherence:perform coherence checking'
|
||||||
|
'borrowck-stats:gather borrowck statistics'
|
||||||
|
"borrowck-note-pure:note where purity is req'd"
|
||||||
|
"borrowck-note-loan:note where loans are req'd"
|
||||||
|
'no-landing-pads:omit landing pads for unwinding'
|
||||||
|
'debug-llvm:enable debug output from LLVM'
|
||||||
|
'count-type-sizes:count the sizes of aggregate types'
|
||||||
|
'meta-stats:gather metadata statistics'
|
||||||
|
'no-opt:do not optimize, even if -O is passed'
|
||||||
|
'no-monomorphic-collapse:do not collapse template instantiations'
|
||||||
|
'print-link-args:Print the arguments passed to the linker'
|
||||||
|
'gc:Garbage collect shared data (experimental)'
|
||||||
|
'jit:Execute using JIT (experimental)'
|
||||||
|
'extra-debug-info:Extra debugging info (experimental)'
|
||||||
|
'debug-info:Produce debug info (experimental)'
|
||||||
|
'static:Use or produce static libraries or binaries (experimental)'
|
||||||
|
'no-debug-borrows:do not show where borrow checks fail'
|
||||||
|
'lint-llvm:Run the LLVM lint pass on the pre-optimization IR'
|
||||||
|
)
|
||||||
|
|
||||||
|
_rustc_opts_fun_lint(){
|
||||||
|
_values -s , 'options' \
|
||||||
|
"$_rustc_opts_lint[@]"
|
||||||
|
}
|
||||||
|
|
||||||
|
_rustc_opts_fun_debug(){
|
||||||
|
_describe 'options' _rustc_opts_debug
|
||||||
|
}
|
||||||
|
|
||||||
|
_arguments -s : \
|
||||||
|
'(-W --warn)'{-W,--warn}'[Set lint warnings]:lint options:_rustc_opts_fun_lint' \
|
||||||
|
'(-A --allow)'{-A,--allow}'[Set lint allowed]:lint options:_rustc_opts_fun_lint' \
|
||||||
|
'(-D --deny)'{-D,--deny}'[Set lint denied]:lint options:_rustc_opts_fun_lint' \
|
||||||
|
'(-F --forbid)'{-F,--forbid}'[Set lint forbidden]:lint options:_rustc_opts_fun_lint' \
|
||||||
|
'*-Z[Set internal debugging options]:debug options:_rustc_opts_fun_debug' \
|
||||||
|
"$_rustc_opts_switches[@]" \
|
||||||
|
'*::files:_files -g "*.rs"'
|
@ -1,321 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Managed vectors
|
|
||||||
|
|
||||||
use cast::transmute;
|
|
||||||
use kinds::Copy;
|
|
||||||
use iter;
|
|
||||||
use option::Option;
|
|
||||||
use ptr::addr_of;
|
|
||||||
use sys;
|
|
||||||
use uint;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
/// Code for dealing with @-vectors. This is pretty incomplete, and
|
|
||||||
/// contains a bunch of duplication from the code for ~-vectors.
|
|
||||||
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc;
|
|
||||||
use sys;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
#[abi = "cdecl"]
|
|
||||||
#[link_name = "rustrt"]
|
|
||||||
pub extern {
|
|
||||||
pub unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
|
|
||||||
++v: **vec::raw::VecRepr,
|
|
||||||
++n: libc::size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of elements the vector can hold without reallocating
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn capacity<T>(v: @[T]) -> uint {
|
|
||||||
unsafe {
|
|
||||||
let repr: **raw::VecRepr =
|
|
||||||
::cast::reinterpret_cast(&addr_of(&v));
|
|
||||||
(**repr).unboxed.alloc / sys::size_of::<T>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a vector by calling a provided function with an argument
|
|
||||||
* function that pushes an element to the back of a vector.
|
|
||||||
* This version takes an initial size for the vector.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * size - An initial size of the vector to reserve
|
|
||||||
* * builder - A function that will construct the vector. It recieves
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the vector being constructed.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn build_sized<A>(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] {
|
|
||||||
let mut vec: @[A] = @[];
|
|
||||||
unsafe { raw::reserve(&mut vec, size); }
|
|
||||||
builder(|+x| unsafe { raw::push(&mut vec, x) });
|
|
||||||
return unsafe { transmute(vec) };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a vector by calling a provided function with an argument
|
|
||||||
* function that pushes an element to the back of a vector.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * builder - A function that will construct the vector. It recieves
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the vector being constructed.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn build<A>(builder: &fn(push: &fn(v: A))) -> @[A] {
|
|
||||||
build_sized(4, builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a vector by calling a provided function with an argument
|
|
||||||
* function that pushes an element to the back of a vector.
|
|
||||||
* This version takes an initial size for the vector.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * size - An option, maybe containing initial size of the vector to reserve
|
|
||||||
* * builder - A function that will construct the vector. It recieves
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the vector being constructed.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn build_sized_opt<A>(size: Option<uint>,
|
|
||||||
builder: &fn(push: &fn(v: A)))
|
|
||||||
-> @[A] {
|
|
||||||
build_sized(size.get_or_default(4), builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appending
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] {
|
|
||||||
do build_sized(lhs.len() + rhs.len()) |push| {
|
|
||||||
for vec::each(lhs) |x| { push(*x); }
|
|
||||||
for uint::range(0, rhs.len()) |i| { push(rhs[i]); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Apply a function to each element of a vector and return the results
|
|
||||||
pub fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] {
|
|
||||||
do build_sized(v.len()) |push| {
|
|
||||||
for vec::each(v) |elem| {
|
|
||||||
push(f(elem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes an immutable vector.
|
|
||||||
*
|
|
||||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
||||||
* to the value returned by the function `op`.
|
|
||||||
*/
|
|
||||||
pub fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
|
|
||||||
do build_sized(n_elts) |push| {
|
|
||||||
let mut i: uint = 0u;
|
|
||||||
while i < n_elts { push(op(i)); i += 1u; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes an immutable vector.
|
|
||||||
*
|
|
||||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
||||||
* to the value `t`.
|
|
||||||
*/
|
|
||||||
pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> @[T] {
|
|
||||||
do build_sized(n_elts) |push| {
|
|
||||||
let mut i: uint = 0u;
|
|
||||||
while i < n_elts { push(copy t); i += 1u; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes an immutable managed vector by moving all the
|
|
||||||
* elements from an owned vector.
|
|
||||||
*/
|
|
||||||
pub fn from_owned<T>(v: ~[T]) -> @[T] {
|
|
||||||
let mut av = @[];
|
|
||||||
unsafe {
|
|
||||||
raw::reserve(&mut av, v.len());
|
|
||||||
do vec::consume(v) |_i, x| {
|
|
||||||
raw::push(&mut av, x);
|
|
||||||
}
|
|
||||||
transmute(av)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes an immutable managed vector by copying all the
|
|
||||||
* elements of a slice.
|
|
||||||
*/
|
|
||||||
pub fn from_slice<T:Copy>(v: &[T]) -> @[T] {
|
|
||||||
from_fn(v.len(), |i| v[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
pub mod traits {
|
|
||||||
use at_vec::append;
|
|
||||||
use kinds::Copy;
|
|
||||||
use ops::Add;
|
|
||||||
|
|
||||||
impl<'self,T:Copy> Add<&'self const [T],@[T]> for @[T] {
|
|
||||||
#[inline(always)]
|
|
||||||
fn add(&self, rhs: & &'self const [T]) -> @[T] {
|
|
||||||
append(*self, (*rhs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod traits {}
|
|
||||||
|
|
||||||
pub mod raw {
|
|
||||||
use at_vec::{capacity, rustrt};
|
|
||||||
use cast::transmute;
|
|
||||||
use libc;
|
|
||||||
use unstable::intrinsics::{move_val_init};
|
|
||||||
use ptr::addr_of;
|
|
||||||
use ptr;
|
|
||||||
use sys;
|
|
||||||
use uint;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
pub type VecRepr = vec::raw::VecRepr;
|
|
||||||
pub type SliceRepr = vec::raw::SliceRepr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the length of a vector
|
|
||||||
*
|
|
||||||
* This will explicitly set the size of the vector, without actually
|
|
||||||
* modifing its buffers, so it is up to the caller to ensure that
|
|
||||||
* the vector is actually the specified size.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn set_len<T>(v: @[T], new_len: uint) {
|
|
||||||
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(&v));
|
|
||||||
(**repr).unboxed.fill = new_len * sys::size_of::<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn push<T>(v: &mut @[T], initval: T) {
|
|
||||||
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
|
|
||||||
let fill = (**repr).unboxed.fill;
|
|
||||||
if (**repr).unboxed.alloc > fill {
|
|
||||||
push_fast(v, initval);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
push_slow(v, initval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)] // really pretty please
|
|
||||||
pub unsafe fn push_fast<T>(v: &mut @[T], initval: T) {
|
|
||||||
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
|
|
||||||
let fill = (**repr).unboxed.fill;
|
|
||||||
(**repr).unboxed.fill += sys::size_of::<T>();
|
|
||||||
let p = addr_of(&((**repr).unboxed.data));
|
|
||||||
let p = ptr::offset(p, fill) as *mut T;
|
|
||||||
move_val_init(&mut(*p), initval);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn push_slow<T>(v: &mut @[T], initval: T) {
|
|
||||||
reserve_at_least(&mut *v, v.len() + 1u);
|
|
||||||
push_fast(v, initval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reserves capacity for exactly `n` elements in the given vector.
|
|
||||||
*
|
|
||||||
* If the capacity for `v` is already equal to or greater than the
|
|
||||||
* requested capacity, then no action is taken.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * v - A vector
|
|
||||||
* * n - The number of elements to reserve space for
|
|
||||||
*/
|
|
||||||
pub unsafe fn reserve<T>(v: &mut @[T], n: uint) {
|
|
||||||
// Only make the (slow) call into the runtime if we have to
|
|
||||||
if capacity(*v) < n {
|
|
||||||
let ptr: **VecRepr = transmute(v);
|
|
||||||
rustrt::vec_reserve_shared_actual(sys::get_type_desc::<T>(),
|
|
||||||
ptr, n as libc::size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reserves capacity for at least `n` elements in the given vector.
|
|
||||||
*
|
|
||||||
* This function will over-allocate in order to amortize the
|
|
||||||
* allocation costs in scenarios where the caller may need to
|
|
||||||
* repeatedly reserve additional space.
|
|
||||||
*
|
|
||||||
* If the capacity for `v` is already equal to or greater than the
|
|
||||||
* requested capacity, then no action is taken.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * v - A vector
|
|
||||||
* * n - The number of elements to reserve space for
|
|
||||||
*/
|
|
||||||
pub unsafe fn reserve_at_least<T>(v: &mut @[T], n: uint) {
|
|
||||||
reserve(v, uint::next_power_of_two(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test() {
|
|
||||||
// Some code that could use that, then:
|
|
||||||
fn seq_range(lo: uint, hi: uint) -> @[uint] {
|
|
||||||
do build |push| {
|
|
||||||
for uint::range(lo, hi) |i| {
|
|
||||||
push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(seq_range(10, 15), @[10, 11, 12, 13, 14]);
|
|
||||||
assert!(from_fn(5, |x| x+1) == @[1, 2, 3, 4, 5]);
|
|
||||||
assert!(from_elem(5, 3.14) == @[3.14, 3.14, 3.14, 3.14, 3.14]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn append_test() {
|
|
||||||
assert!(@[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_owned() {
|
|
||||||
assert!(from_owned::<int>(~[]) == @[]);
|
|
||||||
assert!(from_owned(~[true]) == @[true]);
|
|
||||||
assert!(from_owned(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
|
|
||||||
assert!(from_owned(~[~"abc", ~"123"]) == @[~"abc", ~"123"]);
|
|
||||||
assert!(from_owned(~[~[42]]) == @[~[42]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_slice() {
|
|
||||||
assert!(from_slice::<int>([]) == @[]);
|
|
||||||
assert!(from_slice([true]) == @[true]);
|
|
||||||
assert!(from_slice([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
|
|
||||||
assert!(from_slice([@"abc", @"123"]) == @[@"abc", @"123"]);
|
|
||||||
assert!(from_slice([@[42]]) == @[@[42]]);
|
|
||||||
}
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
|
|
||||||
//! Boolean logic
|
|
||||||
|
|
||||||
use option::{None, Option, Some};
|
|
||||||
use from_str::FromStr;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp;
|
|
||||||
|
|
||||||
/// Negation / inverse
|
|
||||||
pub fn not(v: bool) -> bool { !v }
|
|
||||||
|
|
||||||
/// Conjunction
|
|
||||||
pub fn and(a: bool, b: bool) -> bool { a && b }
|
|
||||||
|
|
||||||
/// Disjunction
|
|
||||||
pub fn or(a: bool, b: bool) -> bool { a || b }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclusive or
|
|
||||||
*
|
|
||||||
* Identical to `or(and(a, not(b)), and(not(a), b))`
|
|
||||||
*/
|
|
||||||
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
|
|
||||||
|
|
||||||
/// Implication in the logic, i.e. from `a` follows `b`
|
|
||||||
pub fn implies(a: bool, b: bool) -> bool { !a || b }
|
|
||||||
|
|
||||||
/// true if truth values `a` and `b` are indistinguishable in the logic
|
|
||||||
pub fn eq(a: bool, b: bool) -> bool { a == b }
|
|
||||||
|
|
||||||
/// true if truth values `a` and `b` are distinguishable in the logic
|
|
||||||
pub fn ne(a: bool, b: bool) -> bool { a != b }
|
|
||||||
|
|
||||||
/// true if `v` represents truth in the logic
|
|
||||||
pub fn is_true(v: bool) -> bool { v }
|
|
||||||
|
|
||||||
/// true if `v` represents falsehood in the logic
|
|
||||||
pub fn is_false(v: bool) -> bool { !v }
|
|
||||||
|
|
||||||
/// Parse logic value from `s`
|
|
||||||
impl FromStr for bool {
|
|
||||||
fn from_str(s: &str) -> Option<bool> {
|
|
||||||
if s == "true" {
|
|
||||||
Some(true)
|
|
||||||
} else if s == "false" {
|
|
||||||
Some(false)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert `v` into a string
|
|
||||||
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over all truth values by passing them to `blk` in an unspecified
|
|
||||||
* order
|
|
||||||
*/
|
|
||||||
pub fn all_values(blk: &fn(v: bool)) {
|
|
||||||
blk(true);
|
|
||||||
blk(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// converts truth value to an 8 bit byte
|
|
||||||
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl cmp::Eq for bool {
|
|
||||||
fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
|
|
||||||
fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_bool_from_str() {
|
|
||||||
use from_str::FromStr;
|
|
||||||
|
|
||||||
do all_values |v| {
|
|
||||||
assert!(Some(v) == FromStr::from_str(to_str(v)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_bool_to_str() {
|
|
||||||
assert!(to_str(false) == ~"false");
|
|
||||||
assert!(to_str(true) == ~"true");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_bool_to_bit() {
|
|
||||||
do all_values |v| {
|
|
||||||
assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust;
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
@ -1,154 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Unsafe casting functions
|
|
||||||
|
|
||||||
pub mod rusti {
|
|
||||||
#[abi = "rust-intrinsic"]
|
|
||||||
#[link_name = "rusti"]
|
|
||||||
pub extern "rust-intrinsic" {
|
|
||||||
fn forget<T>(+x: T);
|
|
||||||
fn reinterpret_cast<T, U>(&&e: T) -> U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Casts the value at `src` to U. The two types must have the same length.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
|
|
||||||
rusti::reinterpret_cast(*src)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move a thing into the void
|
|
||||||
*
|
|
||||||
* The forget function will take ownership of the provided value but neglect
|
|
||||||
* to run any required cleanup or memory-management operations on it. This
|
|
||||||
* can be used for various acts of magick, particularly when using
|
|
||||||
* reinterpret_cast on pointer types.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn forget<T>(thing: T) { rusti::forget(thing); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force-increment the reference count on a shared box. If used
|
|
||||||
* carelessly, this can leak the box. Use this in conjunction with transmute
|
|
||||||
* and/or reinterpret_cast when such calls would otherwise scramble a box's
|
|
||||||
* reference count
|
|
||||||
*/
|
|
||||||
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform a value of one type into a value of another type.
|
|
||||||
* Both types must have the same size and alignment.
|
|
||||||
*
|
|
||||||
* # Example
|
|
||||||
*
|
|
||||||
* assert!(transmute("L") == ~[76u8, 0u8]);
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute<L, G>(thing: L) -> G {
|
|
||||||
let newthing: G = reinterpret_cast(&thing);
|
|
||||||
forget(thing);
|
|
||||||
newthing
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Coerce an immutable reference to be mutable.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }
|
|
||||||
|
|
||||||
/// Coerce a mutable reference to be immutable.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_immut<'a,T>(ptr: &'a mut T) -> &'a T {
|
|
||||||
transmute(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Coerce a borrowed pointer to have an arbitrary associated region.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
|
|
||||||
transmute(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Coerce an immutable reference to be mutable.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
|
|
||||||
transmute(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Coerce an immutable reference to be mutable.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
|
|
||||||
transmute(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
|
|
||||||
transmute(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transforms lifetime of the second pointer to match the first.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
|
|
||||||
transmute_region(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transforms lifetime of the second pointer to match the first.
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
|
|
||||||
transmute_region(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Tests
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod tests {
|
|
||||||
use cast::{bump_box_refcount, reinterpret_cast, transmute};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_reinterpret_cast() {
|
|
||||||
assert!(1u == unsafe { reinterpret_cast(&1) });
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_bump_box_refcount() {
|
|
||||||
unsafe {
|
|
||||||
let box = @~"box box box"; // refcount 1
|
|
||||||
bump_box_refcount(box); // refcount 2
|
|
||||||
let ptr: *int = transmute(box); // refcount 2
|
|
||||||
let _box1: @~str = reinterpret_cast(&ptr);
|
|
||||||
let _box2: @~str = reinterpret_cast(&ptr);
|
|
||||||
assert!(*_box1 == ~"box box box");
|
|
||||||
assert!(*_box2 == ~"box box box");
|
|
||||||
// Will destroy _box1 and _box2. Without the bump, this would
|
|
||||||
// use-after-free. With too many bumps, it would leak.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_transmute() {
|
|
||||||
use managed::raw::BoxRepr;
|
|
||||||
unsafe {
|
|
||||||
let x = @100u8;
|
|
||||||
let x: *BoxRepr = transmute(x);
|
|
||||||
assert!((*x).data == 100);
|
|
||||||
let _x: @int = transmute(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_transmute2() {
|
|
||||||
unsafe {
|
|
||||||
assert!(~[76u8, 0u8] == transmute(~"L"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! A mutable, nullable memory location
|
|
||||||
|
|
||||||
use cast::transmute;
|
|
||||||
use prelude::*;
|
|
||||||
|
|
||||||
/*
|
|
||||||
A dynamic, mutable location.
|
|
||||||
|
|
||||||
Similar to a mutable option type, but friendlier.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub struct Cell<T> {
|
|
||||||
mut value: Option<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:cmp::Eq> cmp::Eq for Cell<T> {
|
|
||||||
fn eq(&self, other: &Cell<T>) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let frozen_self: &Option<T> = transmute(&mut self.value);
|
|
||||||
let frozen_other: &Option<T> = transmute(&mut other.value);
|
|
||||||
frozen_self == frozen_other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn ne(&self, other: &Cell<T>) -> bool { !self.eq(other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new full cell with the given value.
|
|
||||||
pub fn Cell<T>(value: T) -> Cell<T> {
|
|
||||||
Cell { value: Some(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty_cell<T>() -> Cell<T> {
|
|
||||||
Cell { value: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T> Cell<T> {
|
|
||||||
/// Yields the value, failing if the cell is empty.
|
|
||||||
fn take(&self) -> T {
|
|
||||||
if self.is_empty() {
|
|
||||||
fail!(~"attempt to take an empty cell");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut value = None;
|
|
||||||
value <-> self.value;
|
|
||||||
value.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the value, failing if the cell is full.
|
|
||||||
fn put_back(&self, value: T) {
|
|
||||||
if !self.is_empty() {
|
|
||||||
fail!(~"attempt to put a value back into a full cell");
|
|
||||||
}
|
|
||||||
self.value = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the cell is empty and false if the cell is full.
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.value.is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calls a closure with a reference to the value.
|
|
||||||
fn with_ref<R>(&self, op: &fn(v: &T) -> R) -> R {
|
|
||||||
let v = self.take();
|
|
||||||
let r = op(&v);
|
|
||||||
self.put_back(v);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_basic() {
|
|
||||||
let value_cell = Cell(~10);
|
|
||||||
assert!(!value_cell.is_empty());
|
|
||||||
let value = value_cell.take();
|
|
||||||
assert!(value == ~10);
|
|
||||||
assert!(value_cell.is_empty());
|
|
||||||
value_cell.put_back(value);
|
|
||||||
assert!(!value_cell.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
fn test_take_empty() {
|
|
||||||
let value_cell = empty_cell::<~int>();
|
|
||||||
value_cell.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
fn test_put_back_non_empty() {
|
|
||||||
let value_cell = Cell(~10);
|
|
||||||
value_cell.put_back(~20);
|
|
||||||
}
|
|
@ -1,348 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Utilities for manipulating the char type
|
|
||||||
|
|
||||||
use option::{None, Option, Some};
|
|
||||||
use str;
|
|
||||||
use u32;
|
|
||||||
use uint;
|
|
||||||
use unicode;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp::Eq;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Lu Uppercase_Letter an uppercase letter
|
|
||||||
Ll Lowercase_Letter a lowercase letter
|
|
||||||
Lt Titlecase_Letter a digraphic character, with first part uppercase
|
|
||||||
Lm Modifier_Letter a modifier letter
|
|
||||||
Lo Other_Letter other letters, including syllables and ideographs
|
|
||||||
Mn Nonspacing_Mark a nonspacing combining mark (zero advance width)
|
|
||||||
Mc Spacing_Mark a spacing combining mark (positive advance width)
|
|
||||||
Me Enclosing_Mark an enclosing combining mark
|
|
||||||
Nd Decimal_Number a decimal digit
|
|
||||||
Nl Letter_Number a letterlike numeric character
|
|
||||||
No Other_Number a numeric character of other type
|
|
||||||
Pc Connector_Punctuation a connecting punctuation mark, like a tie
|
|
||||||
Pd Dash_Punctuation a dash or hyphen punctuation mark
|
|
||||||
Ps Open_Punctuation an opening punctuation mark (of a pair)
|
|
||||||
Pe Close_Punctuation a closing punctuation mark (of a pair)
|
|
||||||
Pi Initial_Punctuation an initial quotation mark
|
|
||||||
Pf Final_Punctuation a final quotation mark
|
|
||||||
Po Other_Punctuation a punctuation mark of other type
|
|
||||||
Sm Math_Symbol a symbol of primarily mathematical use
|
|
||||||
Sc Currency_Symbol a currency sign
|
|
||||||
Sk Modifier_Symbol a non-letterlike modifier symbol
|
|
||||||
So Other_Symbol a symbol of other type
|
|
||||||
Zs Space_Separator a space character (of various non-zero widths)
|
|
||||||
Zl Line_Separator U+2028 LINE SEPARATOR only
|
|
||||||
Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only
|
|
||||||
Cc Control a C0 or C1 control code
|
|
||||||
Cf Format a format control character
|
|
||||||
Cs Surrogate a surrogate code point
|
|
||||||
Co Private_Use a private-use character
|
|
||||||
Cn Unassigned a reserved unassigned code point or a noncharacter
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub use is_alphabetic = unicode::derived_property::Alphabetic;
|
|
||||||
pub use is_XID_start = unicode::derived_property::XID_Start;
|
|
||||||
pub use is_XID_continue = unicode::derived_property::XID_Continue;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether a character is in lower case, defined
|
|
||||||
* in terms of the Unicode General Category 'Ll'
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_lowercase(c: char) -> bool {
|
|
||||||
return unicode::general_category::Ll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether a character is in upper case, defined
|
|
||||||
* in terms of the Unicode General Category 'Lu'.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_uppercase(c: char) -> bool {
|
|
||||||
return unicode::general_category::Lu(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether a character is whitespace. Whitespace is defined in
|
|
||||||
* terms of the Unicode General Categories 'Zs', 'Zl', 'Zp'
|
|
||||||
* additional 'Cc'-category control codes in the range [0x09, 0x0d]
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_whitespace(c: char) -> bool {
|
|
||||||
return ('\x09' <= c && c <= '\x0d')
|
|
||||||
|| unicode::general_category::Zs(c)
|
|
||||||
|| unicode::general_category::Zl(c)
|
|
||||||
|| unicode::general_category::Zp(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether a character is alphanumeric. Alphanumericness is
|
|
||||||
* defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No'
|
|
||||||
* and the Derived Core Property 'Alphabetic'.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_alphanumeric(c: char) -> bool {
|
|
||||||
return unicode::derived_property::Alphabetic(c) ||
|
|
||||||
unicode::general_category::Nd(c) ||
|
|
||||||
unicode::general_category::Nl(c) ||
|
|
||||||
unicode::general_category::No(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether the character is an ASCII character
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_ascii(c: char) -> bool {
|
|
||||||
c - ('\x7F' & c) == '\x00'
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether the character is numeric (Nd, Nl, or No)
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_digit(c: char) -> bool {
|
|
||||||
return unicode::general_category::Nd(c) ||
|
|
||||||
unicode::general_category::Nl(c) ||
|
|
||||||
unicode::general_category::No(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a character parses as a numeric digit in the given radix.
|
|
||||||
* Compared to `is_digit()`, this function only recognizes the ascii
|
|
||||||
* characters `0-9`, `a-z` and `A-Z`.
|
|
||||||
*
|
|
||||||
* Returns `true` if `c` is a valid digit under `radix`, and `false`
|
|
||||||
* otherwise.
|
|
||||||
*
|
|
||||||
* Fails if given a `radix` > 36.
|
|
||||||
*
|
|
||||||
* Note: This just wraps `to_digit()`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_digit_radix(c: char, radix: uint) -> bool {
|
|
||||||
match to_digit(c, radix) {
|
|
||||||
Some(_) => true,
|
|
||||||
None => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a char to the corresponding digit.
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* If `c` is between '0' and '9', the corresponding value
|
|
||||||
* between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is
|
|
||||||
* 'b' or 'B', 11, etc. Returns none if the char does not
|
|
||||||
* refer to a digit in the given radix.
|
|
||||||
*
|
|
||||||
* # Failure
|
|
||||||
* Fails if given a `radix` outside the range `[0..36]`.
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn to_digit(c: char, radix: uint) -> Option<uint> {
|
|
||||||
if radix > 36 {
|
|
||||||
fail!(fmt!("to_digit: radix %? is to high (maximum 36)", radix));
|
|
||||||
}
|
|
||||||
let val = match c {
|
|
||||||
'0' .. '9' => c as uint - ('0' as uint),
|
|
||||||
'a' .. 'z' => c as uint + 10u - ('a' as uint),
|
|
||||||
'A' .. 'Z' => c as uint + 10u - ('A' as uint),
|
|
||||||
_ => return None
|
|
||||||
};
|
|
||||||
if val < radix { Some(val) }
|
|
||||||
else { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a number to the ascii character representing it.
|
|
||||||
*
|
|
||||||
* Returns `Some(char)` if `num` represents one digit under `radix`,
|
|
||||||
* using one character of `0-9` or `a-z`, or `None` if it doesn't.
|
|
||||||
*
|
|
||||||
* Fails if given an `radix` > 36.
|
|
||||||
*/
|
|
||||||
#[inline]
|
|
||||||
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
|
|
||||||
if radix > 36 {
|
|
||||||
fail!(fmt!("from_digit: radix %? is to high (maximum 36)", num));
|
|
||||||
}
|
|
||||||
if num < radix {
|
|
||||||
if num < 10 {
|
|
||||||
Some(('0' as uint + num) as char)
|
|
||||||
} else {
|
|
||||||
Some(('a' as uint + num - 10u) as char)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the hexadecimal unicode escape of a char.
|
|
||||||
*
|
|
||||||
* The rules are as follows:
|
|
||||||
*
|
|
||||||
* - chars in [0,0xff] get 2-digit escapes: `\\xNN`
|
|
||||||
* - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
|
|
||||||
* - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
|
|
||||||
*/
|
|
||||||
pub fn escape_unicode(c: char) -> ~str {
|
|
||||||
let s = u32::to_str_radix(c as u32, 16u);
|
|
||||||
let (c, pad) = (if c <= '\xff' { ('x', 2u) }
|
|
||||||
else if c <= '\uffff' { ('u', 4u) }
|
|
||||||
else { ('U', 8u) });
|
|
||||||
assert!(str::len(s) <= pad);
|
|
||||||
let mut out = ~"\\";
|
|
||||||
unsafe {
|
|
||||||
str::push_str(&mut out, str::from_char(c));
|
|
||||||
for uint::range(str::len(s), pad) |_i|
|
|
||||||
{ str::push_str(&mut out, ~"0"); }
|
|
||||||
str::push_str(&mut out, s);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a 'default' ASCII and C++11-like char-literal escape of a char.
|
|
||||||
*
|
|
||||||
* The default is chosen with a bias toward producing literals that are
|
|
||||||
* legal in a variety of languages, including C++11 and similar C-family
|
|
||||||
* languages. The exact rules are:
|
|
||||||
*
|
|
||||||
* - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
|
|
||||||
* - Single-quote, double-quote and backslash chars are backslash-escaped.
|
|
||||||
* - Any other chars in the range [0x20,0x7e] are not escaped.
|
|
||||||
* - Any other chars are given hex unicode escapes; see `escape_unicode`.
|
|
||||||
*/
|
|
||||||
pub fn escape_default(c: char) -> ~str {
|
|
||||||
match c {
|
|
||||||
'\t' => ~"\\t",
|
|
||||||
'\r' => ~"\\r",
|
|
||||||
'\n' => ~"\\n",
|
|
||||||
'\\' => ~"\\\\",
|
|
||||||
'\'' => ~"\\'",
|
|
||||||
'"' => ~"\\\"",
|
|
||||||
'\x20' .. '\x7e' => str::from_char(c),
|
|
||||||
_ => escape_unicode(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare two chars
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* -1 if a < b, 0 if a == b, +1 if a > b
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn cmp(a: char, b: char) -> int {
|
|
||||||
return if b > a { -1 }
|
|
||||||
else if b < a { 1 }
|
|
||||||
else { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl Eq for char {
|
|
||||||
fn eq(&self, other: &char) -> bool { (*self) == (*other) }
|
|
||||||
fn ne(&self, other: &char) -> bool { (*self) != (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_lowercase() {
|
|
||||||
assert!(is_lowercase('a'));
|
|
||||||
assert!(is_lowercase('ö'));
|
|
||||||
assert!(is_lowercase('ß'));
|
|
||||||
assert!(!is_lowercase('Ü'));
|
|
||||||
assert!(!is_lowercase('P'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_uppercase() {
|
|
||||||
assert!(!is_uppercase('h'));
|
|
||||||
assert!(!is_uppercase('ä'));
|
|
||||||
assert!(!is_uppercase('ß'));
|
|
||||||
assert!(is_uppercase('Ö'));
|
|
||||||
assert!(is_uppercase('T'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_whitespace() {
|
|
||||||
assert!(is_whitespace(' '));
|
|
||||||
assert!(is_whitespace('\u2007'));
|
|
||||||
assert!(is_whitespace('\t'));
|
|
||||||
assert!(is_whitespace('\n'));
|
|
||||||
|
|
||||||
assert!(!is_whitespace('a'));
|
|
||||||
assert!(!is_whitespace('_'));
|
|
||||||
assert!(!is_whitespace('\u0000'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_digit() {
|
|
||||||
assert_eq!(to_digit('0', 10u), Some(0u));
|
|
||||||
assert_eq!(to_digit('1', 2u), Some(1u));
|
|
||||||
assert_eq!(to_digit('2', 3u), Some(2u));
|
|
||||||
assert_eq!(to_digit('9', 10u), Some(9u));
|
|
||||||
assert_eq!(to_digit('a', 16u), Some(10u));
|
|
||||||
assert_eq!(to_digit('A', 16u), Some(10u));
|
|
||||||
assert_eq!(to_digit('b', 16u), Some(11u));
|
|
||||||
assert_eq!(to_digit('B', 16u), Some(11u));
|
|
||||||
assert_eq!(to_digit('z', 36u), Some(35u));
|
|
||||||
assert_eq!(to_digit('Z', 36u), Some(35u));
|
|
||||||
|
|
||||||
assert!(to_digit(' ', 10u).is_none());
|
|
||||||
assert!(to_digit('$', 36u).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_ascii() {
|
|
||||||
assert!(str::all(~"banana", is_ascii));
|
|
||||||
assert!(! str::all(~"ประเทศไทย中华Việt Nam", is_ascii));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_digit() {
|
|
||||||
assert!(is_digit('2'));
|
|
||||||
assert!(is_digit('7'));
|
|
||||||
assert!(! is_digit('c'));
|
|
||||||
assert!(! is_digit('i'));
|
|
||||||
assert!(! is_digit('z'));
|
|
||||||
assert!(! is_digit('Q'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_escape_default() {
|
|
||||||
assert_eq!(escape_default('\n'), ~"\\n");
|
|
||||||
assert_eq!(escape_default('\r'), ~"\\r");
|
|
||||||
assert_eq!(escape_default('\''), ~"\\'");
|
|
||||||
assert_eq!(escape_default('"'), ~"\\\"");
|
|
||||||
assert_eq!(escape_default(' '), ~" ");
|
|
||||||
assert_eq!(escape_default('a'), ~"a");
|
|
||||||
assert_eq!(escape_default('~'), ~"~");
|
|
||||||
assert_eq!(escape_default('\x00'), ~"\\x00");
|
|
||||||
assert_eq!(escape_default('\x1f'), ~"\\x1f");
|
|
||||||
assert_eq!(escape_default('\x7f'), ~"\\x7f");
|
|
||||||
assert_eq!(escape_default('\xff'), ~"\\xff");
|
|
||||||
assert_eq!(escape_default('\u011b'), ~"\\u011b");
|
|
||||||
assert_eq!(escape_default('\U0001d4b6'), ~"\\U0001d4b6");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_escape_unicode() {
|
|
||||||
assert_eq!(escape_unicode('\x00'), ~"\\x00");
|
|
||||||
assert_eq!(escape_unicode('\n'), ~"\\x0a");
|
|
||||||
assert_eq!(escape_unicode(' '), ~"\\x20");
|
|
||||||
assert_eq!(escape_unicode('a'), ~"\\x61");
|
|
||||||
assert_eq!(escape_unicode('\u011b'), ~"\\u011b");
|
|
||||||
assert_eq!(escape_unicode('\U0001d4b6'), ~"\\U0001d4b6");
|
|
||||||
}
|
|
@ -1,229 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[doc(hidden)];
|
|
||||||
|
|
||||||
use libc::{c_char, c_void, intptr_t, uintptr_t};
|
|
||||||
use ptr::mut_null;
|
|
||||||
use repr::BoxRepr;
|
|
||||||
use sys::TypeDesc;
|
|
||||||
use cast::transmute;
|
|
||||||
|
|
||||||
#[cfg(notest)] use ptr::to_unsafe_ptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime structures
|
|
||||||
*
|
|
||||||
* NB: These must match the representation in the C++ runtime.
|
|
||||||
*/
|
|
||||||
|
|
||||||
type DropGlue<'self> = &'self fn(**TypeDesc, *c_void);
|
|
||||||
type FreeGlue<'self> = &'self fn(**TypeDesc, *c_void);
|
|
||||||
|
|
||||||
type TaskID = uintptr_t;
|
|
||||||
|
|
||||||
struct StackSegment { priv opaque: () }
|
|
||||||
struct Scheduler { priv opaque: () }
|
|
||||||
struct SchedulerLoop { priv opaque: () }
|
|
||||||
struct Kernel { priv opaque: () }
|
|
||||||
struct Env { priv opaque: () }
|
|
||||||
struct AllocHeader { priv opaque: () }
|
|
||||||
struct MemoryRegion { priv opaque: () }
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86")]
|
|
||||||
#[cfg(target_arch="arm")]
|
|
||||||
struct Registers {
|
|
||||||
data: [u32, ..16]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="mips")]
|
|
||||||
struct Registers {
|
|
||||||
data: [u32, ..32]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86")]
|
|
||||||
#[cfg(target_arch="arm")]
|
|
||||||
#[cfg(target_arch="mips")]
|
|
||||||
struct Context {
|
|
||||||
regs: Registers,
|
|
||||||
next: *Context,
|
|
||||||
pad: [u32, ..3]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86_64")]
|
|
||||||
struct Registers {
|
|
||||||
data: [u64, ..22]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86_64")]
|
|
||||||
struct Context {
|
|
||||||
regs: Registers,
|
|
||||||
next: *Context,
|
|
||||||
pad: uintptr_t
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BoxedRegion {
|
|
||||||
env: *Env,
|
|
||||||
backing_region: *MemoryRegion,
|
|
||||||
live_allocs: *BoxRepr
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86")]
|
|
||||||
#[cfg(target_arch="arm")]
|
|
||||||
#[cfg(target_arch="mips")]
|
|
||||||
struct Task {
|
|
||||||
// Public fields
|
|
||||||
refcount: intptr_t, // 0
|
|
||||||
id: TaskID, // 4
|
|
||||||
pad: [u32, ..2], // 8
|
|
||||||
ctx: Context, // 16
|
|
||||||
stack_segment: *StackSegment, // 96
|
|
||||||
runtime_sp: uintptr_t, // 100
|
|
||||||
scheduler: *Scheduler, // 104
|
|
||||||
scheduler_loop: *SchedulerLoop, // 108
|
|
||||||
|
|
||||||
// Fields known only to the runtime
|
|
||||||
kernel: *Kernel, // 112
|
|
||||||
name: *c_char, // 116
|
|
||||||
list_index: i32, // 120
|
|
||||||
boxed_region: BoxedRegion // 128
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch="x86_64")]
|
|
||||||
struct Task {
|
|
||||||
// Public fields
|
|
||||||
refcount: intptr_t,
|
|
||||||
id: TaskID,
|
|
||||||
ctx: Context,
|
|
||||||
stack_segment: *StackSegment,
|
|
||||||
runtime_sp: uintptr_t,
|
|
||||||
scheduler: *Scheduler,
|
|
||||||
scheduler_loop: *SchedulerLoop,
|
|
||||||
|
|
||||||
// Fields known only to the runtime
|
|
||||||
kernel: *Kernel,
|
|
||||||
name: *c_char,
|
|
||||||
list_index: i32,
|
|
||||||
boxed_region: BoxedRegion
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Box annihilation
|
|
||||||
*
|
|
||||||
* This runs at task death to free all boxes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct AnnihilateStats {
|
|
||||||
n_total_boxes: uint,
|
|
||||||
n_unique_boxes: uint,
|
|
||||||
n_bytes_freed: uint
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) {
|
|
||||||
use managed;
|
|
||||||
|
|
||||||
let task: *Task = transmute(rustrt::rust_get_task());
|
|
||||||
let box = (*task).boxed_region.live_allocs;
|
|
||||||
let mut box: *mut BoxRepr = transmute(copy box);
|
|
||||||
while box != mut_null() {
|
|
||||||
let next = transmute(copy (*box).header.next);
|
|
||||||
let uniq =
|
|
||||||
(*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE;
|
|
||||||
|
|
||||||
if ! f(box, uniq) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
box = next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
fn debug_mem() -> bool {
|
|
||||||
::rt::env::get().debug_mem
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn debug_mem() -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
|
|
||||||
#[cfg(notest)]
|
|
||||||
#[lang="annihilate"]
|
|
||||||
pub unsafe fn annihilate() {
|
|
||||||
use unstable::lang::local_free;
|
|
||||||
use io::WriterUtil;
|
|
||||||
use io;
|
|
||||||
use libc;
|
|
||||||
use sys;
|
|
||||||
use managed;
|
|
||||||
|
|
||||||
let mut stats = AnnihilateStats {
|
|
||||||
n_total_boxes: 0,
|
|
||||||
n_unique_boxes: 0,
|
|
||||||
n_bytes_freed: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pass 1: Make all boxes immortal.
|
|
||||||
for each_live_alloc |box, uniq| {
|
|
||||||
stats.n_total_boxes += 1;
|
|
||||||
if uniq {
|
|
||||||
stats.n_unique_boxes += 1;
|
|
||||||
} else {
|
|
||||||
(*box).header.ref_count = managed::raw::RC_IMMORTAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass 2: Drop all boxes.
|
|
||||||
for each_live_alloc |box, uniq| {
|
|
||||||
if !uniq {
|
|
||||||
let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc);
|
|
||||||
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
|
|
||||||
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass 3: Free all boxes.
|
|
||||||
for each_live_alloc |box, uniq| {
|
|
||||||
if !uniq {
|
|
||||||
stats.n_bytes_freed +=
|
|
||||||
(*((*box).header.type_desc)).size
|
|
||||||
+ sys::size_of::<BoxRepr>();
|
|
||||||
local_free(transmute(box));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if debug_mem() {
|
|
||||||
// We do logging here w/o allocation.
|
|
||||||
let dbg = libc::STDERR_FILENO as io::fd_t;
|
|
||||||
dbg.write_str("annihilator stats:");
|
|
||||||
dbg.write_str("\n total_boxes: ");
|
|
||||||
dbg.write_uint(stats.n_total_boxes);
|
|
||||||
dbg.write_str("\n unique_boxes: ");
|
|
||||||
dbg.write_uint(stats.n_unique_boxes);
|
|
||||||
dbg.write_str("\n bytes_freed: ");
|
|
||||||
dbg.write_uint(stats.n_bytes_freed);
|
|
||||||
dbg.write_str("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Bindings to the runtime
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc::c_void;
|
|
||||||
|
|
||||||
#[link_name = "rustrt"]
|
|
||||||
pub extern {
|
|
||||||
#[rust_stack]
|
|
||||||
// FIXME (#4386): Unable to make following method private.
|
|
||||||
pub unsafe fn rust_get_task() -> *c_void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*! The Clone trait for types that cannot be "implicitly copied"
|
|
||||||
|
|
||||||
In Rust, some simple types are "implicitly copyable" and when you
|
|
||||||
assign them or pass them as arguments, the receiver will get a copy,
|
|
||||||
leaving the original value in place. These types do not require
|
|
||||||
allocation to copy and do not have finalizers (i.e. they do not
|
|
||||||
contain owned pointers or implement `Drop`), so the compiler considers
|
|
||||||
them cheap and safe to copy and automatically implements the `Copy`
|
|
||||||
trait for them. For other types copies must be made explicitly,
|
|
||||||
by convention implementing the `Clone` trait and calling the
|
|
||||||
`clone` method.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub trait Clone {
|
|
||||||
fn clone(&self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for () {
|
|
||||||
#[inline(always)]
|
|
||||||
fn clone(&self) -> () { () }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Clone> Clone for ~T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn clone(&self) -> ~T { ~(**self).clone() }
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! clone_impl(
|
|
||||||
($t:ty) => {
|
|
||||||
impl Clone for $t {
|
|
||||||
#[inline(always)]
|
|
||||||
fn clone(&self) -> $t { *self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
clone_impl!(int)
|
|
||||||
clone_impl!(i8)
|
|
||||||
clone_impl!(i16)
|
|
||||||
clone_impl!(i32)
|
|
||||||
clone_impl!(i64)
|
|
||||||
|
|
||||||
clone_impl!(uint)
|
|
||||||
clone_impl!(u8)
|
|
||||||
clone_impl!(u16)
|
|
||||||
clone_impl!(u32)
|
|
||||||
clone_impl!(u64)
|
|
||||||
|
|
||||||
clone_impl!(float)
|
|
||||||
clone_impl!(f32)
|
|
||||||
clone_impl!(f64)
|
|
||||||
|
|
||||||
clone_impl!(bool)
|
|
||||||
clone_impl!(char)
|
|
@ -1,183 +0,0 @@
|
|||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
|
|
||||||
The `Ord` and `Eq` comparison traits
|
|
||||||
|
|
||||||
This module contains the definition of both `Ord` and `Eq` which define
|
|
||||||
the common interfaces for doing comparison. Both are language items
|
|
||||||
that the compiler uses to implement the comparison operators. Rust code
|
|
||||||
may implement `Ord` to overload the `<`, `<=`, `>`, and `>=` operators,
|
|
||||||
and `Eq` to overload the `==` and `!=` operators.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait for values that can be compared for equality and inequality.
|
|
||||||
*
|
|
||||||
* This trait allows partial equality, where types can be unordered instead of strictly equal or
|
|
||||||
* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both
|
|
||||||
* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11).
|
|
||||||
*
|
|
||||||
* Eventually, this will be implemented by default for types that implement `TotalEq`.
|
|
||||||
*/
|
|
||||||
#[lang="eq"]
|
|
||||||
pub trait Eq {
|
|
||||||
fn eq(&self, other: &Self) -> bool;
|
|
||||||
fn ne(&self, other: &Self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for equality comparisons where `a == b` and `a != b` are strict inverses.
|
|
||||||
pub trait TotalEq {
|
|
||||||
fn equals(&self, other: &Self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! totaleq_impl(
|
|
||||||
($t:ty) => {
|
|
||||||
impl TotalEq for $t {
|
|
||||||
#[inline(always)]
|
|
||||||
fn equals(&self, other: &$t) -> bool { *self == *other }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
totaleq_impl!(bool)
|
|
||||||
|
|
||||||
totaleq_impl!(u8)
|
|
||||||
totaleq_impl!(u16)
|
|
||||||
totaleq_impl!(u32)
|
|
||||||
totaleq_impl!(u64)
|
|
||||||
|
|
||||||
totaleq_impl!(i8)
|
|
||||||
totaleq_impl!(i16)
|
|
||||||
totaleq_impl!(i32)
|
|
||||||
totaleq_impl!(i64)
|
|
||||||
|
|
||||||
totaleq_impl!(int)
|
|
||||||
totaleq_impl!(uint)
|
|
||||||
|
|
||||||
#[deriving(Eq)]
|
|
||||||
pub enum Ordering { Less, Equal, Greater }
|
|
||||||
|
|
||||||
/// Trait for types that form a total order
|
|
||||||
pub trait TotalOrd: TotalEq {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! totalord_impl(
|
|
||||||
($t:ty) => {
|
|
||||||
impl TotalOrd for $t {
|
|
||||||
#[inline(always)]
|
|
||||||
fn cmp(&self, other: &$t) -> Ordering {
|
|
||||||
if *self < *other { Less }
|
|
||||||
else if *self > *other { Greater }
|
|
||||||
else { Equal }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
totalord_impl!(u8)
|
|
||||||
totalord_impl!(u16)
|
|
||||||
totalord_impl!(u32)
|
|
||||||
totalord_impl!(u64)
|
|
||||||
|
|
||||||
totalord_impl!(i8)
|
|
||||||
totalord_impl!(i16)
|
|
||||||
totalord_impl!(i32)
|
|
||||||
totalord_impl!(i64)
|
|
||||||
|
|
||||||
totalord_impl!(int)
|
|
||||||
totalord_impl!(uint)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait for values that can be compared for a sort-order.
|
|
||||||
*
|
|
||||||
* Eventually this may be simplified to only require
|
|
||||||
* an `le` method, with the others generated from
|
|
||||||
* default implementations. However it should remain
|
|
||||||
* possible to implement the others separately, for
|
|
||||||
* compatibility with floating-point NaN semantics
|
|
||||||
* (cf. IEEE 754-2008 section 5.11).
|
|
||||||
*/
|
|
||||||
#[lang="ord"]
|
|
||||||
pub trait Ord {
|
|
||||||
fn lt(&self, other: &Self) -> bool;
|
|
||||||
fn le(&self, other: &Self) -> bool;
|
|
||||||
fn ge(&self, other: &Self) -> bool;
|
|
||||||
fn gt(&self, other: &Self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lt<T:Ord>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).lt(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn le<T:Ord>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).le(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn eq<T:Eq>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).eq(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ne<T:Eq>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).ne(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ge<T:Ord>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).ge(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn gt<T:Ord>(v1: &T, v2: &T) -> bool {
|
|
||||||
(*v1).gt(v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The equivalence relation. Two values may be equivalent even if they are
|
|
||||||
/// of different types. The most common use case for this relation is
|
|
||||||
/// container types; e.g. it is often desirable to be able to use `&str`
|
|
||||||
/// values to look up entries in a container with `~str` keys.
|
|
||||||
pub trait Equiv<T> {
|
|
||||||
fn equiv(&self, other: &T) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn min<T:Ord>(v1: T, v2: T) -> T {
|
|
||||||
if v1 < v2 { v1 } else { v2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn max<T:Ord>(v1: T, v2: T) -> T {
|
|
||||||
if v1 > v2 { v1 } else { v2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
#[test]
|
|
||||||
fn test_int_totalord() {
|
|
||||||
assert_eq!(5.cmp(&10), Less);
|
|
||||||
assert_eq!(10.cmp(&5), Greater);
|
|
||||||
assert_eq!(5.cmp(&5), Equal);
|
|
||||||
assert_eq!((-5).cmp(&12), Less);
|
|
||||||
assert_eq!(12.cmp(-5), Greater);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_int_totaleq() {
|
|
||||||
assert!(5.equals(&5));
|
|
||||||
assert!(!2.equals(&17));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,470 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Message passing
|
|
||||||
*/
|
|
||||||
|
|
||||||
use cast;
|
|
||||||
use either::{Either, Left, Right};
|
|
||||||
use kinds::Owned;
|
|
||||||
use option::{Option, Some, None};
|
|
||||||
use uint;
|
|
||||||
use unstable;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
use pipes::{recv, try_recv, wait_many, peek, PacketHeader};
|
|
||||||
|
|
||||||
// FIXME #5160: Making this public exposes some plumbing from
|
|
||||||
// pipes. Needs some refactoring
|
|
||||||
pub use pipes::Selectable;
|
|
||||||
|
|
||||||
/// A trait for things that can send multiple messages.
|
|
||||||
pub trait GenericChan<T> {
|
|
||||||
/// Sends a message.
|
|
||||||
fn send(&self, x: T);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Things that can send multiple messages and can detect when the receiver
|
|
||||||
/// is closed
|
|
||||||
pub trait GenericSmartChan<T> {
|
|
||||||
/// Sends a message, or report if the receiver has closed the connection.
|
|
||||||
fn try_send(&self, x: T) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait for things that can receive multiple messages.
|
|
||||||
pub trait GenericPort<T> {
|
|
||||||
/// Receives a message, or fails if the connection closes.
|
|
||||||
fn recv(&self) -> T;
|
|
||||||
|
|
||||||
/** Receives a message, or returns `none` if
|
|
||||||
the connection is closed or closes.
|
|
||||||
*/
|
|
||||||
fn try_recv(&self) -> Option<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ports that can `peek`
|
|
||||||
pub trait Peekable<T> {
|
|
||||||
/// Returns true if a message is available
|
|
||||||
fn peek(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of an endpoint that is ready to receive.
|
|
||||||
pub fn selecti<T: Selectable>(endpoints: &[T]) -> uint {
|
|
||||||
wait_many(endpoints)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns 0 or 1 depending on which endpoint is ready to receive
|
|
||||||
pub fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) ->
|
|
||||||
Either<(), ()> {
|
|
||||||
match wait_many([a.header(), b.header()]) {
|
|
||||||
0 => Left(()),
|
|
||||||
1 => Right(()),
|
|
||||||
_ => fail!(~"wait returned unexpected index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Streams - Make pipes a little easier in general.
|
|
||||||
|
|
||||||
proto! streamp (
|
|
||||||
Open:send<T: Owned> {
|
|
||||||
data(T) -> Open<T>
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
struct Chan_<T> {
|
|
||||||
mut endp: Option<streamp::client::Open<T>>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An endpoint that can send many messages.
|
|
||||||
pub enum Chan<T> {
|
|
||||||
Chan_(Chan_<T>)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Port_<T> {
|
|
||||||
mut endp: Option<streamp::server::Open<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An endpoint that can receive many messages.
|
|
||||||
pub enum Port<T> {
|
|
||||||
Port_(Port_<T>)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates a `(chan, port)` pair.
|
|
||||||
|
|
||||||
These allow sending or receiving an unlimited number of messages.
|
|
||||||
|
|
||||||
*/
|
|
||||||
pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) {
|
|
||||||
let (c, s) = streamp::init();
|
|
||||||
|
|
||||||
(Port_(Port_ { endp: Some(s) }), Chan_(Chan_{ endp: Some(c) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an inherent method so that imports of GenericChan are not
|
|
||||||
// required.
|
|
||||||
pub impl<T: Owned> Chan<T> {
|
|
||||||
fn send(&self, x: T) { chan_send(self, x) }
|
|
||||||
fn try_send(&self, x: T) -> bool { chan_try_send(self, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> GenericChan<T> for Chan<T> {
|
|
||||||
fn send(&self, x: T) { chan_send(self, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn chan_send<T:Owned>(self: &Chan<T>, x: T) {
|
|
||||||
let mut endp = None;
|
|
||||||
endp <-> self.endp;
|
|
||||||
self.endp = Some(
|
|
||||||
streamp::client::data(endp.unwrap(), x))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> GenericSmartChan<T> for Chan<T> {
|
|
||||||
fn try_send(&self, x: T) -> bool {
|
|
||||||
chan_try_send(self, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn chan_try_send<T:Owned>(self: &Chan<T>, x: T) -> bool {
|
|
||||||
let mut endp = None;
|
|
||||||
endp <-> self.endp;
|
|
||||||
match streamp::client::try_data(endp.unwrap(), x) {
|
|
||||||
Some(next) => {
|
|
||||||
self.endp = Some(next);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use an inherent impl so that imports are not required:
|
|
||||||
pub impl<T: Owned> Port<T> {
|
|
||||||
fn recv(&self) -> T { port_recv(self) }
|
|
||||||
fn try_recv(&self) -> Option<T> { port_try_recv(self) }
|
|
||||||
fn peek(&self) -> bool { port_peek(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> GenericPort<T> for Port<T> {
|
|
||||||
// These two calls will prefer the inherent versions above:
|
|
||||||
fn recv(&self) -> T { port_recv(self) }
|
|
||||||
fn try_recv(&self) -> Option<T> { port_try_recv(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_recv<T:Owned>(self: &Port<T>) -> T {
|
|
||||||
let mut endp = None;
|
|
||||||
endp <-> self.endp;
|
|
||||||
let streamp::data(x, endp) = recv(endp.unwrap());
|
|
||||||
self.endp = Some(endp);
|
|
||||||
x
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_try_recv<T:Owned>(self: &Port<T>) -> Option<T> {
|
|
||||||
let mut endp = None;
|
|
||||||
endp <-> self.endp;
|
|
||||||
match try_recv(endp.unwrap()) {
|
|
||||||
Some(streamp::data(x, endp)) => {
|
|
||||||
self.endp = Some(endp);
|
|
||||||
Some(x)
|
|
||||||
}
|
|
||||||
None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> Peekable<T> for Port<T> {
|
|
||||||
fn peek(&self) -> bool { port_peek(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_peek<T:Owned>(self: &Port<T>) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let mut endp = None;
|
|
||||||
endp <-> self.endp;
|
|
||||||
let peek = match &endp {
|
|
||||||
&Some(ref endp) => peek(endp),
|
|
||||||
&None => fail!(~"peeking empty stream")
|
|
||||||
};
|
|
||||||
self.endp <-> endp;
|
|
||||||
peek
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> Selectable for Port<T> {
|
|
||||||
fn header(&self) -> *PacketHeader {
|
|
||||||
unsafe {
|
|
||||||
match self.endp {
|
|
||||||
Some(ref endp) => endp.header(),
|
|
||||||
None => fail!(~"peeking empty stream")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Treat many ports as one.
|
|
||||||
pub struct PortSet<T> {
|
|
||||||
mut ports: ~[Port<T>],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn PortSet<T: Owned>() -> PortSet<T>{
|
|
||||||
PortSet {
|
|
||||||
ports: ~[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use an inherent impl so that imports are not required:
|
|
||||||
pub impl<T:Owned> PortSet<T> {
|
|
||||||
fn recv(&self) -> T { port_set_recv(self) }
|
|
||||||
fn try_recv(&self) -> Option<T> { port_set_try_recv(self) }
|
|
||||||
fn peek(&self) -> bool { port_set_peek(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T: Owned> PortSet<T> {
|
|
||||||
fn add(&self, port: Port<T>) {
|
|
||||||
self.ports.push(port)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chan(&self) -> Chan<T> {
|
|
||||||
let (po, ch) = stream();
|
|
||||||
self.add(po);
|
|
||||||
ch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Owned> GenericPort<T> for PortSet<T> {
|
|
||||||
fn try_recv(&self) -> Option<T> { port_set_try_recv(self) }
|
|
||||||
fn recv(&self) -> T { port_set_recv(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_set_recv<T:Owned>(self: &PortSet<T>) -> T {
|
|
||||||
port_set_try_recv(self).expect("port_set: endpoints closed")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_set_try_recv<T:Owned>(self: &PortSet<T>) -> Option<T> {
|
|
||||||
let mut result = None;
|
|
||||||
// we have to swap the ports array so we aren't borrowing
|
|
||||||
// aliasable mutable memory.
|
|
||||||
let mut ports = ~[];
|
|
||||||
ports <-> self.ports;
|
|
||||||
while result.is_none() && ports.len() > 0 {
|
|
||||||
let i = wait_many(ports);
|
|
||||||
match ports[i].try_recv() {
|
|
||||||
Some(m) => {
|
|
||||||
result = Some(m);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// Remove this port.
|
|
||||||
let _ = ports.swap_remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ports <-> self.ports;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> Peekable<T> for PortSet<T> {
|
|
||||||
fn peek(&self) -> bool { port_set_peek(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn port_set_peek<T:Owned>(self: &PortSet<T>) -> bool {
|
|
||||||
// It'd be nice to use self.port.each, but that version isn't
|
|
||||||
// pure.
|
|
||||||
for uint::range(0, vec::uniq_len(&const self.ports)) |i| {
|
|
||||||
// XXX: Botch pending demuting.
|
|
||||||
unsafe {
|
|
||||||
let port: &Port<T> = cast::transmute(&mut self.ports[i]);
|
|
||||||
if port.peek() { return true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A channel that can be shared between many senders.
|
|
||||||
pub type SharedChan<T> = unstable::Exclusive<Chan<T>>;
|
|
||||||
|
|
||||||
pub impl<T: Owned> SharedChan<T> {
|
|
||||||
fn send(&self, x: T) { shared_chan_send(self, x) }
|
|
||||||
fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> GenericChan<T> for SharedChan<T> {
|
|
||||||
fn send(&self, x: T) { shared_chan_send(self, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shared_chan_send<T:Owned>(self: &SharedChan<T>, x: T) {
|
|
||||||
let mut xx = Some(x);
|
|
||||||
do self.with_imm |chan| {
|
|
||||||
let mut x = None;
|
|
||||||
x <-> xx;
|
|
||||||
chan.send(x.unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned> GenericSmartChan<T> for SharedChan<T> {
|
|
||||||
fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn shared_chan_try_send<T:Owned>(self: &SharedChan<T>, x: T) -> bool {
|
|
||||||
let mut xx = Some(x);
|
|
||||||
do self.with_imm |chan| {
|
|
||||||
let mut x = None;
|
|
||||||
x <-> xx;
|
|
||||||
chan.try_send(x.unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a `chan` into a `shared_chan`.
|
|
||||||
pub fn SharedChan<T:Owned>(c: Chan<T>) -> SharedChan<T> {
|
|
||||||
unstable::exclusive(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a message from one of two endpoints.
|
|
||||||
pub trait Select2<T: Owned, U: Owned> {
|
|
||||||
/// Receive a message or return `None` if a connection closes.
|
|
||||||
fn try_select(&self) -> Either<Option<T>, Option<U>>;
|
|
||||||
/// Receive a message or fail if a connection closes.
|
|
||||||
fn select(&self) -> Either<T, U>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Owned, U: Owned,
|
|
||||||
Left: Selectable + GenericPort<T>,
|
|
||||||
Right: Selectable + GenericPort<U>>
|
|
||||||
Select2<T, U> for (Left, Right) {
|
|
||||||
|
|
||||||
fn select(&self) -> Either<T, U> {
|
|
||||||
match *self {
|
|
||||||
(ref lp, ref rp) => match select2i(lp, rp) {
|
|
||||||
Left(()) => Left (lp.recv()),
|
|
||||||
Right(()) => Right(rp.recv())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_select(&self) -> Either<Option<T>, Option<U>> {
|
|
||||||
match *self {
|
|
||||||
(ref lp, ref rp) => match select2i(lp, rp) {
|
|
||||||
Left(()) => Left (lp.try_recv()),
|
|
||||||
Right(()) => Right(rp.try_recv())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proto! oneshot (
|
|
||||||
Oneshot:send<T:Owned> {
|
|
||||||
send(T) -> !
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/// The send end of a oneshot pipe.
|
|
||||||
pub type ChanOne<T> = oneshot::client::Oneshot<T>;
|
|
||||||
/// The receive end of a oneshot pipe.
|
|
||||||
pub type PortOne<T> = oneshot::server::Oneshot<T>;
|
|
||||||
|
|
||||||
/// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair.
|
|
||||||
pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) {
|
|
||||||
let (chan, port) = oneshot::init();
|
|
||||||
(port, chan)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T: Owned> PortOne<T> {
|
|
||||||
fn recv(self) -> T { recv_one(self) }
|
|
||||||
fn try_recv(self) -> Option<T> { try_recv_one(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T: Owned> ChanOne<T> {
|
|
||||||
fn send(self, data: T) { send_one(self, data) }
|
|
||||||
fn try_send(self, data: T) -> bool { try_send_one(self, data) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive a message from a oneshot pipe, failing if the connection was
|
|
||||||
* closed.
|
|
||||||
*/
|
|
||||||
pub fn recv_one<T: Owned>(port: PortOne<T>) -> T {
|
|
||||||
let oneshot::send(message) = recv(port);
|
|
||||||
message
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a message from a oneshot pipe unless the connection was closed.
|
|
||||||
pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> {
|
|
||||||
let message = try_recv(port);
|
|
||||||
|
|
||||||
if message.is_none() { None }
|
|
||||||
else {
|
|
||||||
let oneshot::send(message) = message.unwrap();
|
|
||||||
Some(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a message on a oneshot pipe, failing if the connection was closed.
|
|
||||||
pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) {
|
|
||||||
oneshot::client::send(chan, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message on a oneshot pipe, or return false if the connection was
|
|
||||||
* closed.
|
|
||||||
*/
|
|
||||||
pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T)
|
|
||||||
-> bool {
|
|
||||||
oneshot::client::try_send(chan, data).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod test {
|
|
||||||
use either::Right;
|
|
||||||
use super::{Chan, Port, oneshot, recv_one, stream};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_select2() {
|
|
||||||
let (p1, c1) = stream();
|
|
||||||
let (p2, c2) = stream();
|
|
||||||
|
|
||||||
c1.send(~"abc");
|
|
||||||
|
|
||||||
match (p1, p2).select() {
|
|
||||||
Right(_) => fail!(),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
c2.send(123);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_oneshot() {
|
|
||||||
let (c, p) = oneshot::init();
|
|
||||||
|
|
||||||
oneshot::client::send(c, ());
|
|
||||||
|
|
||||||
recv_one(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_peek_terminated() {
|
|
||||||
let (port, chan): (Port<int>, Chan<int>) = stream();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Destroy the channel
|
|
||||||
let _chan = chan;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(!port.peek());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Container traits
|
|
||||||
|
|
||||||
use option::Option;
|
|
||||||
|
|
||||||
pub trait Container {
|
|
||||||
/// Return the number of elements in the container
|
|
||||||
fn len(&const self) -> uint;
|
|
||||||
|
|
||||||
/// Return true if the container contains no elements
|
|
||||||
fn is_empty(&const self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Mutable: Container {
|
|
||||||
/// Clear the container, removing all values.
|
|
||||||
fn clear(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Map<K, V>: Mutable {
|
|
||||||
/// Return true if the map contains a value for the specified key
|
|
||||||
fn contains_key(&self, key: &K) -> bool;
|
|
||||||
|
|
||||||
/// Visit all keys
|
|
||||||
fn each_key(&self, f: &fn(&K) -> bool);
|
|
||||||
|
|
||||||
/// Visit all values
|
|
||||||
fn each_value(&self, f: &fn(&V) -> bool);
|
|
||||||
|
|
||||||
/// Iterate over the map and mutate the contained values
|
|
||||||
fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool);
|
|
||||||
|
|
||||||
/// Return a reference to the value corresponding to the key
|
|
||||||
fn find(&self, key: &K) -> Option<&'self V>;
|
|
||||||
|
|
||||||
/// Return a mutable reference to the value corresponding to the key
|
|
||||||
fn find_mut(&mut self, key: &K) -> Option<&'self mut V>;
|
|
||||||
|
|
||||||
/// Insert a key-value pair into the map. An existing value for a
|
|
||||||
/// key is replaced by the new value. Return true if the key did
|
|
||||||
/// not already exist in the map.
|
|
||||||
fn insert(&mut self, key: K, value: V) -> bool;
|
|
||||||
|
|
||||||
/// Remove a key-value pair from the map. Return true if the key
|
|
||||||
/// was present in the map, otherwise false.
|
|
||||||
fn remove(&mut self, key: &K) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Set<T>: Mutable {
|
|
||||||
/// Return true if the set contains a value
|
|
||||||
fn contains(&self, value: &T) -> bool;
|
|
||||||
|
|
||||||
/// Add a value to the set. Return true if the value was not already
|
|
||||||
/// present in the set.
|
|
||||||
fn insert(&mut self, value: T) -> bool;
|
|
||||||
|
|
||||||
/// Remove a value from the set. Return true if the value was
|
|
||||||
/// present in the set.
|
|
||||||
fn remove(&mut self, value: &T) -> bool;
|
|
||||||
|
|
||||||
/// Return true if the set has no elements in common with `other`.
|
|
||||||
/// This is equivalent to checking for an empty intersection.
|
|
||||||
fn is_disjoint(&self, other: &Self) -> bool;
|
|
||||||
|
|
||||||
/// Return true if the set is a subset of another
|
|
||||||
fn is_subset(&self, other: &Self) -> bool;
|
|
||||||
|
|
||||||
/// Return true if the set is a superset of another
|
|
||||||
fn is_superset(&self, other: &Self) -> bool;
|
|
||||||
|
|
||||||
/// Visit the values representing the difference
|
|
||||||
fn difference(&self, other: &Self, f: &fn(&T) -> bool);
|
|
||||||
|
|
||||||
/// Visit the values representing the symmetric difference
|
|
||||||
fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool);
|
|
||||||
|
|
||||||
/// Visit the values representing the intersection
|
|
||||||
fn intersection(&self, other: &Self, f: &fn(&T) -> bool);
|
|
||||||
|
|
||||||
/// Visit the values representing the union
|
|
||||||
fn union(&self, other: &Self, f: &fn(&T) -> bool);
|
|
||||||
}
|
|
@ -1,260 +0,0 @@
|
|||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
|
|
||||||
# The Rust core library
|
|
||||||
|
|
||||||
The Rust core library provides runtime features required by the language,
|
|
||||||
including the task scheduler and memory allocators, as well as library
|
|
||||||
support for Rust built-in types, platform abstractions, and other commonly
|
|
||||||
used features.
|
|
||||||
|
|
||||||
`core` includes modules corresponding to each of the integer types, each of
|
|
||||||
the floating point types, the `bool` type, tuples, characters, strings
|
|
||||||
(`str`), vectors (`vec`), managed boxes (`managed`), owned boxes (`owned`),
|
|
||||||
and unsafe and borrowed pointers (`ptr`). Additionally, `core` provides
|
|
||||||
pervasive types (`option` and `result`), task creation and communication
|
|
||||||
primitives (`task`, `comm`), platform abstractions (`os` and `path`), basic
|
|
||||||
I/O abstractions (`io`), common traits (`kinds`, `ops`, `cmp`, `num`,
|
|
||||||
`to_str`), and complete bindings to the C standard library (`libc`).
|
|
||||||
|
|
||||||
# Core injection and the Rust prelude
|
|
||||||
|
|
||||||
`core` is imported at the topmost level of every crate by default, as
|
|
||||||
if the first line of each crate was
|
|
||||||
|
|
||||||
extern mod core;
|
|
||||||
|
|
||||||
This means that the contents of core can be accessed from from any context
|
|
||||||
with the `core::` path prefix, as in `use core::vec`, `use core::task::spawn`,
|
|
||||||
etc.
|
|
||||||
|
|
||||||
Additionally, `core` contains a `prelude` module that reexports many of the
|
|
||||||
most common core modules, types and traits. The contents of the prelude are
|
|
||||||
imported into every *module* by default. Implicitly, all modules behave as if
|
|
||||||
they contained the following prologue:
|
|
||||||
|
|
||||||
use core::prelude::*;
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#[link(name = "core",
|
|
||||||
vers = "0.6",
|
|
||||||
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
|
|
||||||
url = "https://github.com/mozilla/rust/tree/master/src/libcore")];
|
|
||||||
|
|
||||||
#[comment = "The Rust core library"];
|
|
||||||
#[license = "MIT/ASL2"];
|
|
||||||
#[crate_type = "lib"];
|
|
||||||
|
|
||||||
|
|
||||||
// Don't link to core. We are core.
|
|
||||||
#[no_core];
|
|
||||||
|
|
||||||
#[warn(vecs_implicitly_copyable)];
|
|
||||||
#[deny(non_camel_case_types)];
|
|
||||||
#[allow(deprecated_mutable_fields)];
|
|
||||||
#[allow(deprecated_drop)];
|
|
||||||
|
|
||||||
// Make core testable by not duplicating lang items. See #2912
|
|
||||||
#[cfg(test)] extern mod realcore(name = "core", vers = "0.6");
|
|
||||||
#[cfg(test)] pub use kinds = realcore::kinds;
|
|
||||||
#[cfg(test)] pub use ops = realcore::ops;
|
|
||||||
#[cfg(test)] pub use cmp = realcore::cmp;
|
|
||||||
|
|
||||||
/* Reexported core operators */
|
|
||||||
|
|
||||||
pub use kinds::{Const, Copy, Owned, Durable};
|
|
||||||
pub use ops::{Drop};
|
|
||||||
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not};
|
|
||||||
pub use ops::{BitAnd, BitOr, BitXor};
|
|
||||||
pub use ops::{Shl, Shr, Index};
|
|
||||||
|
|
||||||
|
|
||||||
/* Reexported types and traits */
|
|
||||||
|
|
||||||
pub use option::{Option, Some, None};
|
|
||||||
pub use result::{Result, Ok, Err};
|
|
||||||
|
|
||||||
pub use path::Path;
|
|
||||||
pub use path::GenericPath;
|
|
||||||
pub use path::WindowsPath;
|
|
||||||
pub use path::PosixPath;
|
|
||||||
|
|
||||||
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
|
||||||
pub use str::{StrSlice};
|
|
||||||
pub use container::{Container, Mutable};
|
|
||||||
pub use vec::{CopyableVector, ImmutableVector};
|
|
||||||
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
|
|
||||||
pub use vec::{OwnedVector, OwnedCopyableVector};
|
|
||||||
pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
|
|
||||||
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
|
|
||||||
|
|
||||||
pub use num::NumCast;
|
|
||||||
pub use ptr::Ptr;
|
|
||||||
pub use to_str::ToStr;
|
|
||||||
pub use clone::Clone;
|
|
||||||
|
|
||||||
// On Linux, link to the runtime with -lrt.
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod linkhack {
|
|
||||||
#[link_args="-lrustrt -lrt"]
|
|
||||||
#[link_args = "-lpthread"]
|
|
||||||
extern {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Prelude. */
|
|
||||||
|
|
||||||
pub mod prelude;
|
|
||||||
|
|
||||||
/* Primitive types */
|
|
||||||
|
|
||||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/int.rs"]
|
|
||||||
pub mod int;
|
|
||||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i8.rs"]
|
|
||||||
pub mod i8;
|
|
||||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i16.rs"]
|
|
||||||
pub mod i16;
|
|
||||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i32.rs"]
|
|
||||||
pub mod i32;
|
|
||||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i64.rs"]
|
|
||||||
pub mod i64;
|
|
||||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/uint.rs"]
|
|
||||||
pub mod uint;
|
|
||||||
|
|
||||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u8.rs"]
|
|
||||||
pub mod u8;
|
|
||||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u16.rs"]
|
|
||||||
pub mod u16;
|
|
||||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u32.rs"]
|
|
||||||
pub mod u32;
|
|
||||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u64.rs"]
|
|
||||||
pub mod u64;
|
|
||||||
|
|
||||||
#[path = "num/float.rs"]
|
|
||||||
pub mod float;
|
|
||||||
#[path = "num/f32.rs"]
|
|
||||||
pub mod f32;
|
|
||||||
#[path = "num/f64.rs"]
|
|
||||||
pub mod f64;
|
|
||||||
|
|
||||||
pub mod nil;
|
|
||||||
pub mod bool;
|
|
||||||
pub mod char;
|
|
||||||
pub mod tuple;
|
|
||||||
|
|
||||||
pub mod vec;
|
|
||||||
pub mod at_vec;
|
|
||||||
pub mod str;
|
|
||||||
|
|
||||||
pub mod ptr;
|
|
||||||
pub mod owned;
|
|
||||||
pub mod managed;
|
|
||||||
|
|
||||||
|
|
||||||
/* Core language traits */
|
|
||||||
|
|
||||||
#[cfg(notest)] pub mod kinds;
|
|
||||||
#[cfg(notest)] pub mod ops;
|
|
||||||
#[cfg(notest)] pub mod cmp;
|
|
||||||
|
|
||||||
|
|
||||||
/* Common traits */
|
|
||||||
|
|
||||||
pub mod from_str;
|
|
||||||
#[path = "num/num.rs"]
|
|
||||||
pub mod num;
|
|
||||||
pub mod iter;
|
|
||||||
pub mod to_str;
|
|
||||||
pub mod to_bytes;
|
|
||||||
pub mod clone;
|
|
||||||
pub mod io;
|
|
||||||
pub mod hash;
|
|
||||||
pub mod container;
|
|
||||||
|
|
||||||
|
|
||||||
/* Common data structures */
|
|
||||||
|
|
||||||
pub mod option;
|
|
||||||
pub mod result;
|
|
||||||
pub mod either;
|
|
||||||
pub mod hashmap;
|
|
||||||
pub mod cell;
|
|
||||||
pub mod trie;
|
|
||||||
|
|
||||||
|
|
||||||
/* Tasks and communication */
|
|
||||||
|
|
||||||
#[path = "task/mod.rs"]
|
|
||||||
pub mod task;
|
|
||||||
pub mod comm;
|
|
||||||
pub mod pipes;
|
|
||||||
|
|
||||||
|
|
||||||
/* Runtime and platform support */
|
|
||||||
|
|
||||||
pub mod gc;
|
|
||||||
pub mod libc;
|
|
||||||
pub mod os;
|
|
||||||
pub mod path;
|
|
||||||
pub mod rand;
|
|
||||||
pub mod run;
|
|
||||||
pub mod sys;
|
|
||||||
pub mod cast;
|
|
||||||
pub mod mutable;
|
|
||||||
pub mod flate;
|
|
||||||
pub mod repr;
|
|
||||||
pub mod cleanup;
|
|
||||||
pub mod reflect;
|
|
||||||
pub mod condition;
|
|
||||||
pub mod logging;
|
|
||||||
pub mod util;
|
|
||||||
|
|
||||||
|
|
||||||
/* Unsupported interfaces */
|
|
||||||
|
|
||||||
// Private APIs
|
|
||||||
pub mod unstable;
|
|
||||||
|
|
||||||
/* For internal use, not exported */
|
|
||||||
|
|
||||||
pub mod unicode;
|
|
||||||
#[path = "num/cmath.rs"]
|
|
||||||
pub mod cmath;
|
|
||||||
pub mod stackwalk;
|
|
||||||
#[path = "rt/mod.rs"]
|
|
||||||
pub mod rt;
|
|
||||||
|
|
||||||
// A curious inner-module that's not exported that contains the binding
|
|
||||||
// 'core' so that macro-expanded references to core::error and such
|
|
||||||
// can be resolved within libcore.
|
|
||||||
#[doc(hidden)]
|
|
||||||
mod core {
|
|
||||||
pub use clone;
|
|
||||||
pub use cmp;
|
|
||||||
pub use condition;
|
|
||||||
pub use option;
|
|
||||||
pub use kinds;
|
|
||||||
pub use sys;
|
|
||||||
pub use pipes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust;
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
@ -1,275 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! A type that represents one of two alternatives
|
|
||||||
|
|
||||||
use cmp::Eq;
|
|
||||||
use kinds::Copy;
|
|
||||||
use result::Result;
|
|
||||||
use result;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
/// The either type
|
|
||||||
#[deriving(Clone, Eq)]
|
|
||||||
pub enum Either<T, U> {
|
|
||||||
Left(T),
|
|
||||||
Right(U)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn either<T, U, V>(f_left: &fn(&T) -> V,
|
|
||||||
f_right: &fn(&U) -> V, value: &Either<T, U>) -> V {
|
|
||||||
/*!
|
|
||||||
* Applies a function based on the given either value
|
|
||||||
*
|
|
||||||
* If `value` is left(T) then `f_left` is applied to its contents, if
|
|
||||||
* `value` is right(U) then `f_right` is applied to its contents, and the
|
|
||||||
* result is returned.
|
|
||||||
*/
|
|
||||||
|
|
||||||
match *value {
|
|
||||||
Left(ref l) => f_left(l),
|
|
||||||
Right(ref r) => f_right(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lefts<T:Copy,U>(eithers: &[Either<T, U>]) -> ~[T] {
|
|
||||||
//! Extracts from a vector of either all the left values
|
|
||||||
|
|
||||||
do vec::build_sized(eithers.len()) |push| {
|
|
||||||
for vec::each(eithers) |elt| {
|
|
||||||
match *elt {
|
|
||||||
Left(ref l) => { push(*l); }
|
|
||||||
_ => { /* fallthrough */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] {
|
|
||||||
//! Extracts from a vector of either all the right values
|
|
||||||
|
|
||||||
do vec::build_sized(eithers.len()) |push| {
|
|
||||||
for vec::each(eithers) |elt| {
|
|
||||||
match *elt {
|
|
||||||
Right(ref r) => { push(*r); }
|
|
||||||
_ => { /* fallthrough */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn partition<T, U>(eithers: ~[Either<T, U>])
|
|
||||||
-> (~[T], ~[U]) {
|
|
||||||
/*!
|
|
||||||
* Extracts from a vector of either all the left values and right values
|
|
||||||
*
|
|
||||||
* Returns a structure containing a vector of left values and a vector of
|
|
||||||
* right values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let mut lefts: ~[T] = ~[];
|
|
||||||
let mut rights: ~[U] = ~[];
|
|
||||||
do vec::consume(eithers) |_i, elt| {
|
|
||||||
match elt {
|
|
||||||
Left(l) => lefts.push(l),
|
|
||||||
Right(r) => rights.push(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (lefts, rights);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn flip<T, U>(eith: Either<T, U>) -> Either<U, T> {
|
|
||||||
//! Flips between left and right of a given either
|
|
||||||
|
|
||||||
match eith {
|
|
||||||
Right(r) => Left(r),
|
|
||||||
Left(l) => Right(l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_result<T, U>(eith: Either<T, U>)
|
|
||||||
-> Result<U, T> {
|
|
||||||
/*!
|
|
||||||
* Converts either::t to a result::t
|
|
||||||
*
|
|
||||||
* Converts an `either` type to a `result` type, making the "right" choice
|
|
||||||
* an ok result, and the "left" choice a fail
|
|
||||||
*/
|
|
||||||
|
|
||||||
match eith {
|
|
||||||
Right(r) => result::Ok(r),
|
|
||||||
Left(l) => result::Err(l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_left<T, U>(eith: &Either<T, U>) -> bool {
|
|
||||||
//! Checks whether the given value is a left
|
|
||||||
|
|
||||||
match *eith { Left(_) => true, _ => false }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_right<T, U>(eith: &Either<T, U>) -> bool {
|
|
||||||
//! Checks whether the given value is a right
|
|
||||||
|
|
||||||
match *eith { Right(_) => true, _ => false }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T {
|
|
||||||
//! Retrieves the value in the left branch. Fails if the either is Right.
|
|
||||||
|
|
||||||
match eith {
|
|
||||||
Left(x) => x,
|
|
||||||
Right(_) => fail!(~"either::unwrap_left Right")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U {
|
|
||||||
//! Retrieves the value in the right branch. Fails if the either is Left.
|
|
||||||
|
|
||||||
match eith {
|
|
||||||
Right(x) => x,
|
|
||||||
Left(_) => fail!(~"either::unwrap_right Left")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T, U> Either<T, U> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V {
|
|
||||||
either(f_left, f_right, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn flip(self) -> Either<U, T> { flip(self) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_result(self) -> Result<U, T> { to_result(self) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_left(&self) -> bool { is_left(self) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_right(&self) -> bool { is_right(self) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn unwrap_left(self) -> T { unwrap_left(self) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn unwrap_right(self) -> U { unwrap_right(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_either_left() {
|
|
||||||
let val = Left(10);
|
|
||||||
fn f_left(x: &int) -> bool { *x == 10 }
|
|
||||||
fn f_right(_x: &uint) -> bool { false }
|
|
||||||
assert!((either(f_left, f_right, &val)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_either_right() {
|
|
||||||
let val = Right(10u);
|
|
||||||
fn f_left(_x: &int) -> bool { false }
|
|
||||||
fn f_right(x: &uint) -> bool { *x == 10u }
|
|
||||||
assert!((either(f_left, f_right, &val)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lefts() {
|
|
||||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
|
||||||
let result = lefts(input);
|
|
||||||
assert_eq!(result, ~[10, 12, 14]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lefts_none() {
|
|
||||||
let input: ~[Either<int, int>] = ~[Right(10), Right(10)];
|
|
||||||
let result = lefts(input);
|
|
||||||
assert_eq!(vec::len(result), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lefts_empty() {
|
|
||||||
let input: ~[Either<int, int>] = ~[];
|
|
||||||
let result = lefts(input);
|
|
||||||
assert_eq!(vec::len(result), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rights() {
|
|
||||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
|
||||||
let result = rights(input);
|
|
||||||
assert_eq!(result, ~[11, 13]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rights_none() {
|
|
||||||
let input: ~[Either<int, int>] = ~[Left(10), Left(10)];
|
|
||||||
let result = rights(input);
|
|
||||||
assert_eq!(vec::len(result), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rights_empty() {
|
|
||||||
let input: ~[Either<int, int>] = ~[];
|
|
||||||
let result = rights(input);
|
|
||||||
assert_eq!(vec::len(result), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_partition() {
|
|
||||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
|
||||||
let (lefts, rights) = partition(input);
|
|
||||||
assert_eq!(lefts[0], 10);
|
|
||||||
assert_eq!(lefts[1], 12);
|
|
||||||
assert_eq!(lefts[2], 14);
|
|
||||||
assert_eq!(rights[0], 11);
|
|
||||||
assert_eq!(rights[1], 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_partition_no_lefts() {
|
|
||||||
let input: ~[Either<int, int>] = ~[Right(10), Right(11)];
|
|
||||||
let (lefts, rights) = partition(input);
|
|
||||||
assert_eq!(vec::len(lefts), 0u);
|
|
||||||
assert_eq!(vec::len(rights), 2u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_partition_no_rights() {
|
|
||||||
let input: ~[Either<int, int>] = ~[Left(10), Left(11)];
|
|
||||||
let (lefts, rights) = partition(input);
|
|
||||||
assert_eq!(vec::len(lefts), 2u);
|
|
||||||
assert_eq!(vec::len(rights), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_partition_empty() {
|
|
||||||
let input: ~[Either<int, int>] = ~[];
|
|
||||||
let (lefts, rights) = partition(input);
|
|
||||||
assert_eq!(vec::len(lefts), 0u);
|
|
||||||
assert_eq!(vec::len(rights), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
||||||
//
|
|
@ -1,107 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
|
|
||||||
Simple compression
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
use libc;
|
|
||||||
use libc::{c_void, size_t, c_int};
|
|
||||||
use ptr;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
#[cfg(test)] use rand;
|
|
||||||
#[cfg(test)] use rand::RngUtil;
|
|
||||||
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc::{c_int, c_void, size_t};
|
|
||||||
|
|
||||||
#[link_name = "rustrt"]
|
|
||||||
pub extern {
|
|
||||||
unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
|
|
||||||
src_buf_len: size_t,
|
|
||||||
pout_len: *size_t,
|
|
||||||
flags: c_int)
|
|
||||||
-> *c_void;
|
|
||||||
|
|
||||||
unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
|
|
||||||
src_buf_len: size_t,
|
|
||||||
pout_len: *size_t,
|
|
||||||
flags: c_int)
|
|
||||||
-> *c_void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static lz_none : c_int = 0x0; // Huffman-coding only.
|
|
||||||
static lz_fast : c_int = 0x1; // LZ with only one probe
|
|
||||||
static lz_norm : c_int = 0x80; // LZ with 128 probes, "normal"
|
|
||||||
static lz_best : c_int = 0xfff; // LZ with 4095 probes, "best"
|
|
||||||
|
|
||||||
pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] {
|
|
||||||
do vec::as_const_buf(bytes) |b, len| {
|
|
||||||
unsafe {
|
|
||||||
let mut outsz : size_t = 0;
|
|
||||||
let res =
|
|
||||||
rustrt::tdefl_compress_mem_to_heap(b as *c_void,
|
|
||||||
len as size_t,
|
|
||||||
ptr::addr_of(&outsz),
|
|
||||||
lz_norm);
|
|
||||||
assert!(res as int != 0);
|
|
||||||
let out = vec::raw::from_buf_raw(res as *u8,
|
|
||||||
outsz as uint);
|
|
||||||
libc::free(res);
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] {
|
|
||||||
do vec::as_const_buf(bytes) |b, len| {
|
|
||||||
unsafe {
|
|
||||||
let mut outsz : size_t = 0;
|
|
||||||
let res =
|
|
||||||
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
|
|
||||||
len as size_t,
|
|
||||||
ptr::addr_of(&outsz),
|
|
||||||
0);
|
|
||||||
assert!(res as int != 0);
|
|
||||||
let out = vec::raw::from_buf_raw(res as *u8,
|
|
||||||
outsz as uint);
|
|
||||||
libc::free(res);
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
|
||||||
fn test_flate_round_trip() {
|
|
||||||
let r = rand::Rng();
|
|
||||||
let mut words = ~[];
|
|
||||||
for 20.times {
|
|
||||||
words.push(r.gen_bytes(r.gen_uint_range(1, 10)));
|
|
||||||
}
|
|
||||||
for 20.times {
|
|
||||||
let mut in = ~[];
|
|
||||||
for 2000.times {
|
|
||||||
in.push_all(r.choose(words));
|
|
||||||
}
|
|
||||||
debug!("de/inflate of %u bytes of random word-sequences",
|
|
||||||
in.len());
|
|
||||||
let cmp = deflate_bytes(in);
|
|
||||||
let out = inflate_bytes(cmp);
|
|
||||||
debug!("%u bytes deflated to %u (%.1f%% size)",
|
|
||||||
in.len(), cmp.len(),
|
|
||||||
100.0 * ((cmp.len() as float) / (in.len() as float)));
|
|
||||||
assert!((in == out));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! The trait for types that can be created from strings
|
|
||||||
|
|
||||||
use option::Option;
|
|
||||||
|
|
||||||
pub trait FromStr {
|
|
||||||
fn from_str(s: &str) -> Option<Self>;
|
|
||||||
}
|
|
@ -1,363 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#[doc(hidden)];
|
|
||||||
|
|
||||||
/*! Precise garbage collector
|
|
||||||
|
|
||||||
The precise GC exposes two functions, gc and
|
|
||||||
cleanup_stack_for_failure. The gc function is the entry point to the
|
|
||||||
garbage collector itself. The cleanup_stack_for_failure is the entry
|
|
||||||
point for GC-based cleanup.
|
|
||||||
|
|
||||||
Precise GC depends on changes to LLVM's GC which add support for
|
|
||||||
automatic rooting and addrspace-based metadata marking. Rather than
|
|
||||||
explicitly rooting pointers with LLVM's gcroot intrinsic, the GC
|
|
||||||
merely creates allocas for pointers, and allows an LLVM pass to
|
|
||||||
automatically infer roots based on the allocas present in a function
|
|
||||||
(and live at a given location). The compiler communicates the type of
|
|
||||||
the pointer to LLVM by setting the addrspace of the pointer type. The
|
|
||||||
compiler then emits a map from addrspace to tydesc, which LLVM then
|
|
||||||
uses to match pointers with their tydesc. The GC reads the metadata
|
|
||||||
table produced by LLVM, and uses it to determine which glue functions
|
|
||||||
to call to free objects on their respective heaps.
|
|
||||||
|
|
||||||
GC-based cleanup is a replacement for landing pads which relies on the
|
|
||||||
GC infrastructure to find pointers on the stack to cleanup. Whereas
|
|
||||||
the normal GC needs to walk task-local heap allocations, the cleanup
|
|
||||||
code needs to walk exchange heap allocations and stack-allocations
|
|
||||||
with destructors.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
use cast;
|
|
||||||
use container::{Map, Set};
|
|
||||||
use io;
|
|
||||||
use libc::{size_t, uintptr_t};
|
|
||||||
use option::{None, Option, Some};
|
|
||||||
use ptr;
|
|
||||||
use hashmap::linear::LinearSet;
|
|
||||||
use stackwalk;
|
|
||||||
use sys;
|
|
||||||
|
|
||||||
pub use stackwalk::Word;
|
|
||||||
|
|
||||||
// Mirrors rust_stack.h stk_seg
|
|
||||||
pub struct StackSegment {
|
|
||||||
prev: *StackSegment,
|
|
||||||
next: *StackSegment,
|
|
||||||
end: uintptr_t,
|
|
||||||
// And other fields which we don't care about...
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc::size_t;
|
|
||||||
use stackwalk::Word;
|
|
||||||
use super::StackSegment;
|
|
||||||
|
|
||||||
#[link_name = "rustrt"]
|
|
||||||
pub extern {
|
|
||||||
#[rust_stack]
|
|
||||||
pub unsafe fn rust_call_tydesc_glue(root: *Word,
|
|
||||||
tydesc: *Word,
|
|
||||||
field: size_t);
|
|
||||||
|
|
||||||
#[rust_stack]
|
|
||||||
pub unsafe fn rust_gc_metadata() -> *Word;
|
|
||||||
|
|
||||||
pub unsafe fn rust_get_stack_segment() -> *StackSegment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U {
|
|
||||||
return cast::reinterpret_cast(&ptr::offset(ptr, count));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn align_to_pointer<T>(ptr: *T) -> *T {
|
|
||||||
let align = sys::min_align_of::<*T>();
|
|
||||||
let ptr: uint = cast::reinterpret_cast(&ptr);
|
|
||||||
let ptr = (ptr + (align - 1)) & -align;
|
|
||||||
return cast::reinterpret_cast(&ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_safe_point_count() -> uint {
|
|
||||||
let module_meta = rustrt::rust_gc_metadata();
|
|
||||||
return *module_meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SafePoint {
|
|
||||||
sp_meta: *Word,
|
|
||||||
fn_meta: *Word,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the safe point metadata for the given program counter, if
|
|
||||||
// any.
|
|
||||||
unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
|
|
||||||
let module_meta = rustrt::rust_gc_metadata();
|
|
||||||
let num_safe_points = *module_meta;
|
|
||||||
let safe_points: *Word = bump(module_meta, 1);
|
|
||||||
|
|
||||||
if ptr::is_null(pc) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME (#2997): Use binary rather than linear search.
|
|
||||||
let mut spi = 0;
|
|
||||||
while spi < num_safe_points {
|
|
||||||
let sp: **Word = bump(safe_points, spi*3);
|
|
||||||
let sp_loc = *sp;
|
|
||||||
if sp_loc == pc {
|
|
||||||
return Some(SafePoint {
|
|
||||||
sp_meta: *bump(sp, 1),
|
|
||||||
fn_meta: *bump(sp, 2),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
spi += 1;
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Visitor<'self> = &'self fn(root: **Word, tydesc: *Word) -> bool;
|
|
||||||
|
|
||||||
// Walks the list of roots for the given safe point, and calls visitor
|
|
||||||
// on each root.
|
|
||||||
unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
|
|
||||||
let fp_bytes: *u8 = cast::reinterpret_cast(&fp);
|
|
||||||
let sp_meta: *u32 = cast::reinterpret_cast(&sp.sp_meta);
|
|
||||||
|
|
||||||
let num_stack_roots = *sp_meta as uint;
|
|
||||||
let num_reg_roots = *ptr::offset(sp_meta, 1) as uint;
|
|
||||||
|
|
||||||
let stack_roots: *u32 = bump(sp_meta, 2);
|
|
||||||
let reg_roots: *u8 = bump(stack_roots, num_stack_roots);
|
|
||||||
let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots));
|
|
||||||
let tydescs: ***Word = bump(addrspaces, num_stack_roots);
|
|
||||||
|
|
||||||
// Stack roots
|
|
||||||
let mut sri = 0;
|
|
||||||
while sri < num_stack_roots {
|
|
||||||
if *ptr::offset(addrspaces, sri) >= 1 {
|
|
||||||
let root =
|
|
||||||
ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word)
|
|
||||||
as **Word;
|
|
||||||
let tydescpp = ptr::offset(tydescs, sri);
|
|
||||||
let tydesc = if ptr::is_not_null(tydescpp) &&
|
|
||||||
ptr::is_not_null(*tydescpp) {
|
|
||||||
**tydescpp
|
|
||||||
} else {
|
|
||||||
ptr::null()
|
|
||||||
};
|
|
||||||
if !visitor(root, tydesc) { return; }
|
|
||||||
}
|
|
||||||
sri += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register roots
|
|
||||||
let mut rri = 0;
|
|
||||||
while rri < num_reg_roots {
|
|
||||||
if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 {
|
|
||||||
// FIXME(#2997): Need to find callee saved registers on the stack.
|
|
||||||
}
|
|
||||||
rri += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is fp contained in segment?
|
|
||||||
unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool {
|
|
||||||
let begin: Word = cast::reinterpret_cast(&segment);
|
|
||||||
let end: Word = cast::reinterpret_cast(&(*segment).end);
|
|
||||||
let frame: Word = cast::reinterpret_cast(&fp);
|
|
||||||
|
|
||||||
return begin <= frame && frame <= end;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Segment { segment: *StackSegment, boundary: bool }
|
|
||||||
|
|
||||||
// Find and return the segment containing the given frame pointer. At
|
|
||||||
// stack segment boundaries, returns true for boundary, so that the
|
|
||||||
// caller can do any special handling to identify where the correct
|
|
||||||
// return address is in the stack frame.
|
|
||||||
unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment)
|
|
||||||
-> Segment {
|
|
||||||
// Check if frame is in either current frame or previous frame.
|
|
||||||
let in_segment = is_frame_in_segment(fp, segment);
|
|
||||||
let in_prev_segment = ptr::is_not_null((*segment).prev) &&
|
|
||||||
is_frame_in_segment(fp, (*segment).prev);
|
|
||||||
|
|
||||||
// If frame is not in either segment, walk down segment list until
|
|
||||||
// we find the segment containing this frame.
|
|
||||||
if !in_segment && !in_prev_segment {
|
|
||||||
let mut segment = segment;
|
|
||||||
while ptr::is_not_null((*segment).next) &&
|
|
||||||
is_frame_in_segment(fp, (*segment).next) {
|
|
||||||
segment = (*segment).next;
|
|
||||||
}
|
|
||||||
return Segment {segment: segment, boundary: false};
|
|
||||||
}
|
|
||||||
|
|
||||||
// If frame is in previous frame, then we're at a boundary.
|
|
||||||
if !in_segment && in_prev_segment {
|
|
||||||
return Segment {segment: (*segment).prev, boundary: true};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we're somewhere on the inside of the frame.
|
|
||||||
return Segment {segment: segment, boundary: false};
|
|
||||||
}
|
|
||||||
|
|
||||||
type Memory = uint;
|
|
||||||
|
|
||||||
static task_local_heap: Memory = 1;
|
|
||||||
static exchange_heap: Memory = 2;
|
|
||||||
static stack: Memory = 4;
|
|
||||||
|
|
||||||
static need_cleanup: Memory = exchange_heap | stack;
|
|
||||||
|
|
||||||
// Walks stack, searching for roots of the requested type, and passes
|
|
||||||
// each root to the visitor.
|
|
||||||
unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
|
|
||||||
let mut segment = rustrt::rust_get_stack_segment();
|
|
||||||
let mut last_ret: *Word = ptr::null();
|
|
||||||
// To avoid collecting memory used by the GC itself, skip stack
|
|
||||||
// frames until past the root GC stack frame. The root GC stack
|
|
||||||
// frame is marked by a sentinel, which is a box pointer stored on
|
|
||||||
// the stack.
|
|
||||||
let mut reached_sentinel = ptr::is_null(sentinel);
|
|
||||||
for stackwalk::walk_stack |frame| {
|
|
||||||
unsafe {
|
|
||||||
let pc = last_ret;
|
|
||||||
let Segment {segment: next_segment, boundary: boundary} =
|
|
||||||
find_segment_for_frame(frame.fp, segment);
|
|
||||||
segment = next_segment;
|
|
||||||
// Each stack segment is bounded by a morestack frame. The
|
|
||||||
// morestack frame includes two return addresses, one for
|
|
||||||
// morestack itself, at the normal offset from the frame
|
|
||||||
// pointer, and then a second return address for the
|
|
||||||
// function prologue (which called morestack after
|
|
||||||
// determining that it had hit the end of the stack).
|
|
||||||
// Since morestack itself takes two parameters, the offset
|
|
||||||
// for this second return address is 3 greater than the
|
|
||||||
// return address for morestack.
|
|
||||||
let ret_offset = if boundary { 4 } else { 1 };
|
|
||||||
last_ret = *ptr::offset(frame.fp, ret_offset) as *Word;
|
|
||||||
|
|
||||||
if ptr::is_null(pc) {
|
|
||||||
loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut delay_reached_sentinel = reached_sentinel;
|
|
||||||
let sp = is_safe_point(pc);
|
|
||||||
match sp {
|
|
||||||
Some(sp_info) => {
|
|
||||||
for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
|
|
||||||
// Skip roots until we see the sentinel.
|
|
||||||
if !reached_sentinel {
|
|
||||||
if root == sentinel {
|
|
||||||
delay_reached_sentinel = true;
|
|
||||||
}
|
|
||||||
loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip null pointers, which can occur when a
|
|
||||||
// unique pointer has already been freed.
|
|
||||||
if ptr::is_null(*root) {
|
|
||||||
loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ptr::is_null(tydesc) {
|
|
||||||
// Root is a generic box.
|
|
||||||
let refcount = **root;
|
|
||||||
if mem | task_local_heap != 0 && refcount != -1 {
|
|
||||||
if !visitor(root, tydesc) { return; }
|
|
||||||
} else if mem | exchange_heap != 0 && refcount == -1 {
|
|
||||||
if !visitor(root, tydesc) { return; }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Root is a non-immediate.
|
|
||||||
if mem | stack != 0 {
|
|
||||||
if !visitor(root, tydesc) { return; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
reached_sentinel = delay_reached_sentinel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gc() {
|
|
||||||
unsafe {
|
|
||||||
// Abort when GC is disabled.
|
|
||||||
if get_safe_point_count() == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| {
|
|
||||||
// FIXME(#2997): Walk roots and mark them.
|
|
||||||
io::stdout().write([46]); // .
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(gc)]
|
|
||||||
fn expect_sentinel() -> bool { true }
|
|
||||||
|
|
||||||
#[cfg(nogc)]
|
|
||||||
fn expect_sentinel() -> bool { false }
|
|
||||||
|
|
||||||
// Entry point for GC-based cleanup. Walks stack looking for exchange
|
|
||||||
// heap and stack allocations requiring drop, and runs all
|
|
||||||
// destructors.
|
|
||||||
//
|
|
||||||
// This should only be called from fail!, as it will drop the roots
|
|
||||||
// which are *live* on the stack, rather than dropping those that are
|
|
||||||
// dead.
|
|
||||||
pub fn cleanup_stack_for_failure() {
|
|
||||||
unsafe {
|
|
||||||
// Abort when GC is disabled.
|
|
||||||
if get_safe_point_count() == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave a sentinel on the stack to mark the current frame. The
|
|
||||||
// stack walker will ignore any frames above the sentinel, thus
|
|
||||||
// avoiding collecting any memory being used by the stack walker
|
|
||||||
// itself.
|
|
||||||
//
|
|
||||||
// However, when core itself is not compiled with GC, then none of
|
|
||||||
// the functions in core will have GC metadata, which means we
|
|
||||||
// won't be able to find the sentinel root on the stack. In this
|
|
||||||
// case, we can safely skip the sentinel since we won't find our
|
|
||||||
// own stack roots on the stack anyway.
|
|
||||||
let sentinel_box = ~0;
|
|
||||||
let sentinel: **Word = if expect_sentinel() {
|
|
||||||
cast::reinterpret_cast(&ptr::addr_of(&sentinel_box))
|
|
||||||
} else {
|
|
||||||
ptr::null()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut roots = LinearSet::new();
|
|
||||||
for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| {
|
|
||||||
// Track roots to avoid double frees.
|
|
||||||
if roots.contains(&*root) {
|
|
||||||
loop;
|
|
||||||
}
|
|
||||||
roots.insert(*root);
|
|
||||||
|
|
||||||
if ptr::is_null(tydesc) {
|
|
||||||
// FIXME #4420: Destroy this box
|
|
||||||
// FIXME #4330: Destroy this box
|
|
||||||
} else {
|
|
||||||
rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,536 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Implementation of SipHash 2-4
|
|
||||||
*
|
|
||||||
* See: http://131002.net/siphash/
|
|
||||||
*
|
|
||||||
* Consider this as a main "general-purpose" hash for all hashtables: it
|
|
||||||
* runs at good speed (competitive with spooky and city) and permits
|
|
||||||
* cryptographically strong _keyed_ hashing. Key your hashtables from a
|
|
||||||
* CPRNG like rand::rng.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use io;
|
|
||||||
use io::Writer;
|
|
||||||
use to_bytes::IterBytes;
|
|
||||||
use uint;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types that can meaningfully be hashed should implement this.
|
|
||||||
*
|
|
||||||
* Note that this trait is likely to change somewhat as it is
|
|
||||||
* closely related to `to_bytes::IterBytes` and in almost all
|
|
||||||
* cases presently the two are (and must be) used together.
|
|
||||||
*
|
|
||||||
* In general, most types only need to implement `IterBytes`,
|
|
||||||
* and the implementation of `Hash` below will take care of
|
|
||||||
* the rest. This is the recommended approach, since constructing
|
|
||||||
* good keyed hash functions is quite difficult.
|
|
||||||
*/
|
|
||||||
pub trait Hash {
|
|
||||||
/**
|
|
||||||
* Compute a "keyed" hash of the value implementing the trait,
|
|
||||||
* taking `k0` and `k1` as "keying" parameters that randomize or
|
|
||||||
* otherwise perturb the hash function in such a way that a
|
|
||||||
* hash table built using such "keyed hash functions" cannot
|
|
||||||
* be made to perform linearly by an attacker controlling the
|
|
||||||
* hashtable's contents.
|
|
||||||
*
|
|
||||||
* In practical terms, we implement this using the SipHash 2-4
|
|
||||||
* function and require most types to only implement the
|
|
||||||
* IterBytes trait, that feeds SipHash.
|
|
||||||
*/
|
|
||||||
fn hash_keyed(&self, k0: u64, k1: u64) -> u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When we have default methods, won't need this.
|
|
||||||
pub trait HashUtil {
|
|
||||||
fn hash(&self) -> u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A:Hash> HashUtil for A {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash(&self) -> u64 { self.hash_keyed(0,0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Streaming hash-functions should implement this.
|
|
||||||
pub trait Streaming {
|
|
||||||
fn input(&self, (&const [u8]));
|
|
||||||
// These can be refactored some when we have default methods.
|
|
||||||
fn result_bytes(&self) -> ~[u8];
|
|
||||||
fn result_str(&self) -> ~str;
|
|
||||||
fn result_u64(&self) -> u64;
|
|
||||||
fn reset(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A:IterBytes> Hash for A {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash_keyed(&self, k0: u64, k1: u64) -> u64 {
|
|
||||||
unsafe {
|
|
||||||
let s = &State(k0, k1);
|
|
||||||
for self.iter_bytes(true) |bytes| {
|
|
||||||
s.input(bytes);
|
|
||||||
}
|
|
||||||
s.result_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_keyed_2<A: IterBytes,
|
|
||||||
B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 {
|
|
||||||
unsafe {
|
|
||||||
let s = &State(k0, k1);
|
|
||||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
s.result_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_keyed_3<A: IterBytes,
|
|
||||||
B: IterBytes,
|
|
||||||
C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 {
|
|
||||||
unsafe {
|
|
||||||
let s = &State(k0, k1);
|
|
||||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
s.result_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_keyed_4<A: IterBytes,
|
|
||||||
B: IterBytes,
|
|
||||||
C: IterBytes,
|
|
||||||
D: IterBytes>(a: &A, b: &B, c: &C, d: &D, k0: u64, k1: u64)
|
|
||||||
-> u64 {
|
|
||||||
unsafe {
|
|
||||||
let s = &State(k0, k1);
|
|
||||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for d.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
s.result_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_keyed_5<A: IterBytes,
|
|
||||||
B: IterBytes,
|
|
||||||
C: IterBytes,
|
|
||||||
D: IterBytes,
|
|
||||||
E: IterBytes>(a: &A, b: &B, c: &C, d: &D, e: &E,
|
|
||||||
k0: u64, k1: u64) -> u64 {
|
|
||||||
unsafe {
|
|
||||||
let s = &State(k0, k1);
|
|
||||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for d.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
for e.iter_bytes(true) |bytes| { s.input(bytes); }
|
|
||||||
s.result_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement State as SipState
|
|
||||||
|
|
||||||
pub type State = SipState;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn State(k0: u64, k1: u64) -> State {
|
|
||||||
SipState(k0, k1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn default_state() -> State {
|
|
||||||
State(0,0)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SipState {
|
|
||||||
k0: u64,
|
|
||||||
k1: u64,
|
|
||||||
mut length: uint, // how many bytes we've processed
|
|
||||||
mut v0: u64, // hash state
|
|
||||||
mut v1: u64,
|
|
||||||
mut v2: u64,
|
|
||||||
mut v3: u64,
|
|
||||||
mut tail: [u8, ..8], // unprocessed bytes
|
|
||||||
mut ntail: uint, // how many bytes in tail are valid
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn SipState(key0: u64, key1: u64) -> SipState {
|
|
||||||
let state = SipState {
|
|
||||||
k0 : key0,
|
|
||||||
k1 : key1,
|
|
||||||
mut length : 0u,
|
|
||||||
mut v0 : 0u64,
|
|
||||||
mut v1 : 0u64,
|
|
||||||
mut v2 : 0u64,
|
|
||||||
mut v3 : 0u64,
|
|
||||||
mut tail : [0u8,0,0,0,0,0,0,0],
|
|
||||||
mut ntail : 0u,
|
|
||||||
};
|
|
||||||
(&state).reset();
|
|
||||||
state
|
|
||||||
}
|
|
||||||
|
|
||||||
// sadly, these macro definitions can't appear later,
|
|
||||||
// because they're needed in the following defs;
|
|
||||||
// this design could be improved.
|
|
||||||
|
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
macro_rules! rotl (
|
|
||||||
($x:expr, $b:expr) =>
|
|
||||||
(($x << $b) | ($x >> (64 - $b)))
|
|
||||||
)
|
|
||||||
|
|
||||||
macro_rules! compress (
|
|
||||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
|
||||||
({
|
|
||||||
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
|
||||||
$v0 = rotl!($v0, 32);
|
|
||||||
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
|
||||||
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
|
||||||
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
|
||||||
$v2 = rotl!($v2, 32);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
impl io::Writer for SipState {
|
|
||||||
|
|
||||||
// Methods for io::writer
|
|
||||||
#[inline(always)]
|
|
||||||
fn write(&self, msg: &const [u8]) {
|
|
||||||
|
|
||||||
let length = msg.len();
|
|
||||||
self.length += length;
|
|
||||||
|
|
||||||
let mut needed = 0u;
|
|
||||||
|
|
||||||
if self.ntail != 0 {
|
|
||||||
needed = 8 - self.ntail;
|
|
||||||
|
|
||||||
if length < needed {
|
|
||||||
let mut t = 0;
|
|
||||||
while t < length {
|
|
||||||
self.tail[self.ntail+t] = msg[t];
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
self.ntail += length;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = 0;
|
|
||||||
while t < needed {
|
|
||||||
self.tail[self.ntail+t] = msg[t];
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = u8to64_le!(self.tail, 0);
|
|
||||||
|
|
||||||
self.v3 ^= m;
|
|
||||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
|
||||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
|
||||||
self.v0 ^= m;
|
|
||||||
|
|
||||||
self.ntail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffered tail is now flushed, process new input.
|
|
||||||
let len = length - needed;
|
|
||||||
let end = len & (!0x7);
|
|
||||||
let left = len & 0x7;
|
|
||||||
|
|
||||||
let mut i = needed;
|
|
||||||
while i < end {
|
|
||||||
let mi = u8to64_le!(msg, i);
|
|
||||||
|
|
||||||
self.v3 ^= mi;
|
|
||||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
|
||||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
|
||||||
self.v0 ^= mi;
|
|
||||||
|
|
||||||
i += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = 0u;
|
|
||||||
while t < left {
|
|
||||||
self.tail[t] = msg[i+t];
|
|
||||||
t += 1
|
|
||||||
}
|
|
||||||
self.ntail = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(&self, _x: int, _s: io::SeekStyle) {
|
|
||||||
fail!();
|
|
||||||
}
|
|
||||||
fn tell(&self) -> uint {
|
|
||||||
self.length
|
|
||||||
}
|
|
||||||
fn flush(&self) -> int {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn get_type(&self) -> io::WriterType {
|
|
||||||
io::File
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Streaming for SipState {
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn input(&self, buf: &const [u8]) {
|
|
||||||
self.write(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn result_u64(&self) -> u64 {
|
|
||||||
let mut v0 = self.v0;
|
|
||||||
let mut v1 = self.v1;
|
|
||||||
let mut v2 = self.v2;
|
|
||||||
let mut v3 = self.v3;
|
|
||||||
|
|
||||||
let mut b : u64 = (self.length as u64 & 0xff) << 56;
|
|
||||||
|
|
||||||
if self.ntail > 0 { b |= self.tail[0] as u64 << 0; }
|
|
||||||
if self.ntail > 1 { b |= self.tail[1] as u64 << 8; }
|
|
||||||
if self.ntail > 2 { b |= self.tail[2] as u64 << 16; }
|
|
||||||
if self.ntail > 3 { b |= self.tail[3] as u64 << 24; }
|
|
||||||
if self.ntail > 4 { b |= self.tail[4] as u64 << 32; }
|
|
||||||
if self.ntail > 5 { b |= self.tail[5] as u64 << 40; }
|
|
||||||
if self.ntail > 6 { b |= self.tail[6] as u64 << 48; }
|
|
||||||
|
|
||||||
v3 ^= b;
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
v0 ^= b;
|
|
||||||
|
|
||||||
v2 ^= 0xff;
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
compress!(v0, v1, v2, v3);
|
|
||||||
|
|
||||||
return (v0 ^ v1 ^ v2 ^ v3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result_bytes(&self) -> ~[u8] {
|
|
||||||
let h = self.result_u64();
|
|
||||||
~[(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(&self) -> ~str {
|
|
||||||
let r = self.result_bytes();
|
|
||||||
let mut s = ~"";
|
|
||||||
for vec::each(r) |b| {
|
|
||||||
s += uint::to_str_radix(*b as uint, 16u);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn reset(&self) {
|
|
||||||
self.length = 0;
|
|
||||||
self.v0 = self.k0 ^ 0x736f6d6570736575;
|
|
||||||
self.v1 = self.k1 ^ 0x646f72616e646f6d;
|
|
||||||
self.v2 = self.k0 ^ 0x6c7967656e657261;
|
|
||||||
self.v3 = self.k1 ^ 0x7465646279746573;
|
|
||||||
self.ntail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_siphash() {
|
|
||||||
let vecs : [[u8, ..8], ..64] = [
|
|
||||||
[ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ],
|
|
||||||
[ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ],
|
|
||||||
[ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ],
|
|
||||||
[ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ],
|
|
||||||
[ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ],
|
|
||||||
[ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ],
|
|
||||||
[ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ],
|
|
||||||
[ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ],
|
|
||||||
[ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ],
|
|
||||||
[ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ],
|
|
||||||
[ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ],
|
|
||||||
[ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ],
|
|
||||||
[ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ],
|
|
||||||
[ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ],
|
|
||||||
[ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ],
|
|
||||||
[ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ],
|
|
||||||
[ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ],
|
|
||||||
[ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ],
|
|
||||||
[ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ],
|
|
||||||
[ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ],
|
|
||||||
[ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ],
|
|
||||||
[ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ],
|
|
||||||
[ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ],
|
|
||||||
[ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ],
|
|
||||||
[ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ],
|
|
||||||
[ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ],
|
|
||||||
[ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ],
|
|
||||||
[ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ],
|
|
||||||
[ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ],
|
|
||||||
[ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ],
|
|
||||||
[ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ],
|
|
||||||
[ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ],
|
|
||||||
[ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ],
|
|
||||||
[ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ],
|
|
||||||
[ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ],
|
|
||||||
[ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ],
|
|
||||||
[ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ],
|
|
||||||
[ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ],
|
|
||||||
[ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ],
|
|
||||||
[ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ],
|
|
||||||
[ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ],
|
|
||||||
[ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ],
|
|
||||||
[ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ],
|
|
||||||
[ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ],
|
|
||||||
[ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ],
|
|
||||||
[ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ],
|
|
||||||
[ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ],
|
|
||||||
[ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ],
|
|
||||||
[ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ],
|
|
||||||
[ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ],
|
|
||||||
[ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ],
|
|
||||||
[ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ],
|
|
||||||
[ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ],
|
|
||||||
[ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ],
|
|
||||||
[ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ],
|
|
||||||
[ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ],
|
|
||||||
[ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ],
|
|
||||||
[ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ],
|
|
||||||
[ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ],
|
|
||||||
[ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ],
|
|
||||||
[ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ],
|
|
||||||
[ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ],
|
|
||||||
[ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ],
|
|
||||||
[ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]
|
|
||||||
];
|
|
||||||
|
|
||||||
let k0 = 0x_07_06_05_04_03_02_01_00_u64;
|
|
||||||
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64;
|
|
||||||
let mut buf : ~[u8] = ~[];
|
|
||||||
let mut t = 0;
|
|
||||||
let stream_inc = &State(k0,k1);
|
|
||||||
let stream_full = &State(k0,k1);
|
|
||||||
|
|
||||||
fn to_hex_str(r: &[u8, ..8]) -> ~str {
|
|
||||||
let mut s = ~"";
|
|
||||||
for vec::each(*r) |b| {
|
|
||||||
s += uint::to_str_radix(*b as uint, 16u);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
while t < 64 {
|
|
||||||
debug!("siphash test %?", t);
|
|
||||||
let vec = u8to64_le!(vecs[t], 0);
|
|
||||||
let out = buf.hash_keyed(k0, k1);
|
|
||||||
debug!("got %?, expected %?", out, vec);
|
|
||||||
assert!(vec == out);
|
|
||||||
|
|
||||||
stream_full.reset();
|
|
||||||
stream_full.input(buf);
|
|
||||||
let f = stream_full.result_str();
|
|
||||||
let i = stream_inc.result_str();
|
|
||||||
let v = to_hex_str(&vecs[t]);
|
|
||||||
debug!("%d: (%s) => inc=%s full=%s", t, v, i, f);
|
|
||||||
|
|
||||||
assert!(f == i && f == v);
|
|
||||||
|
|
||||||
buf += ~[t as u8];
|
|
||||||
stream_inc.input(~[t as u8]);
|
|
||||||
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test] #[cfg(target_arch = "arm")]
|
|
||||||
pub fn test_hash_uint() {
|
|
||||||
let val = 0xdeadbeef_deadbeef_u64;
|
|
||||||
assert!((val as u64).hash() != (val as uint).hash());
|
|
||||||
assert!((val as u32).hash() == (val as uint).hash());
|
|
||||||
}
|
|
||||||
#[test] #[cfg(target_arch = "x86_64")]
|
|
||||||
pub fn test_hash_uint() {
|
|
||||||
let val = 0xdeadbeef_deadbeef_u64;
|
|
||||||
assert!((val as u64).hash() == (val as uint).hash());
|
|
||||||
assert!((val as u32).hash() != (val as uint).hash());
|
|
||||||
}
|
|
||||||
#[test] #[cfg(target_arch = "x86")]
|
|
||||||
pub fn test_hash_uint() {
|
|
||||||
let val = 0xdeadbeef_deadbeef_u64;
|
|
||||||
assert!((val as u64).hash() != (val as uint).hash());
|
|
||||||
assert!((val as u32).hash() == (val as uint).hash());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_hash_idempotent() {
|
|
||||||
let val64 = 0xdeadbeef_deadbeef_u64;
|
|
||||||
val64.hash() == val64.hash();
|
|
||||||
let val32 = 0xdeadbeef_u32;
|
|
||||||
val32.hash() == val32.hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_hash_no_bytes_dropped_64() {
|
|
||||||
let val = 0xdeadbeef_deadbeef_u64;
|
|
||||||
|
|
||||||
assert!(val.hash() != zero_byte(val, 0).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 1).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 2).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 3).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 4).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 5).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 6).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 7).hash());
|
|
||||||
|
|
||||||
fn zero_byte(val: u64, byte: uint) -> u64 {
|
|
||||||
assert!(byte < 8);
|
|
||||||
val & !(0xff << (byte * 8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_hash_no_bytes_dropped_32() {
|
|
||||||
let val = 0xdeadbeef_u32;
|
|
||||||
|
|
||||||
assert!(val.hash() != zero_byte(val, 0).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 1).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 2).hash());
|
|
||||||
assert!(val.hash() != zero_byte(val, 3).hash());
|
|
||||||
|
|
||||||
fn zero_byte(val: u32, byte: uint) -> u32 {
|
|
||||||
assert!(byte < 4);
|
|
||||||
val & !(0xff << (byte * 8))
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
1616
src/libcore/io.rs
1616
src/libcore/io.rs
File diff suppressed because it is too large
Load Diff
@ -1,346 +0,0 @@
|
|||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
|
|
||||||
The iteration traits and common implementation
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
use cmp::{Eq, Ord};
|
|
||||||
use kinds::Copy;
|
|
||||||
use option::{None, Option, Some};
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
/// A function used to initialize the elements of a sequence
|
|
||||||
pub type InitOp<'self,T> = &'self fn(uint) -> T;
|
|
||||||
|
|
||||||
pub trait BaseIter<A> {
|
|
||||||
fn each(&self, blk: &fn(v: &A) -> bool);
|
|
||||||
fn size_hint(&self) -> Option<uint>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ReverseIter<A>: BaseIter<A> {
|
|
||||||
fn each_reverse(&self, blk: &fn(&A) -> bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MutableIter<A>: BaseIter<A> {
|
|
||||||
fn each_mut(&mut self, blk: &fn(&mut A) -> bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ExtendedIter<A> {
|
|
||||||
fn eachi(&self, blk: &fn(uint, v: &A) -> bool);
|
|
||||||
fn all(&self, blk: &fn(&A) -> bool) -> bool;
|
|
||||||
fn any(&self, blk: &fn(&A) -> bool) -> bool;
|
|
||||||
fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B;
|
|
||||||
fn position(&self, f: &fn(&A) -> bool) -> Option<uint>;
|
|
||||||
fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B];
|
|
||||||
fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait EqIter<A:Eq> {
|
|
||||||
fn contains(&self, x: &A) -> bool;
|
|
||||||
fn count(&self, x: &A) -> uint;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Times {
|
|
||||||
fn times(&self, it: &fn() -> bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CopyableIter<A:Copy> {
|
|
||||||
fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A];
|
|
||||||
fn to_vec(&self) -> ~[A];
|
|
||||||
fn find(&self, p: &fn(&A) -> bool) -> Option<A>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CopyableOrderedIter<A:Copy + Ord> {
|
|
||||||
fn min(&self) -> A;
|
|
||||||
fn max(&self) -> A;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CopyableNonstrictIter<A:Copy> {
|
|
||||||
// Like "each", but copies out the value. If the receiver is mutated while
|
|
||||||
// iterating over it, the semantics must not be memory-unsafe but are
|
|
||||||
// otherwise undefined.
|
|
||||||
fn each_val(&const self, f: &fn(A) -> bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A trait for sequences that can be built by imperatively pushing elements
|
|
||||||
// onto them.
|
|
||||||
pub trait Buildable<A> {
|
|
||||||
/**
|
|
||||||
* Builds a buildable sequence by calling a provided function with
|
|
||||||
* an argument function that pushes an element onto the back of
|
|
||||||
* the sequence.
|
|
||||||
* This version takes an initial size for the sequence.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * size - A hint for an initial size of the sequence
|
|
||||||
* * builder - A function that will construct the sequence. It receives
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the sequence being constructed.
|
|
||||||
*/
|
|
||||||
fn build_sized(size: uint, builder: &fn(push: &fn(A))) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn eachi<A,IA:BaseIter<A>>(self: &IA, blk: &fn(uint, &A) -> bool) {
|
|
||||||
let mut i = 0;
|
|
||||||
for self.each |a| {
|
|
||||||
if !blk(i, a) { break; }
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn all<A,IA:BaseIter<A>>(self: &IA, blk: &fn(&A) -> bool) -> bool {
|
|
||||||
for self.each |a| {
|
|
||||||
if !blk(a) { return false; }
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn any<A,IA:BaseIter<A>>(self: &IA, blk: &fn(&A) -> bool) -> bool {
|
|
||||||
for self.each |a| {
|
|
||||||
if blk(a) { return true; }
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: &IA,
|
|
||||||
prd: &fn(&A) -> bool)
|
|
||||||
-> ~[A] {
|
|
||||||
do vec::build_sized_opt(self.size_hint()) |push| {
|
|
||||||
for self.each |a| {
|
|
||||||
if prd(a) { push(*a); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn map_to_vec<A,B,IA:BaseIter<A>>(self: &IA, op: &fn(&A) -> B) -> ~[B] {
|
|
||||||
do vec::build_sized_opt(self.size_hint()) |push| {
|
|
||||||
for self.each |a| {
|
|
||||||
push(op(a));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(self: &IA,
|
|
||||||
op: &fn(&A) -> IB)
|
|
||||||
-> ~[B] {
|
|
||||||
do vec::build |push| {
|
|
||||||
for self.each |a| {
|
|
||||||
for op(a).each |&b| {
|
|
||||||
push(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B, blk: &fn(&B, &A) -> B)
|
|
||||||
-> B {
|
|
||||||
let mut b = b0;
|
|
||||||
for self.each |a| {
|
|
||||||
b = blk(&b, a);
|
|
||||||
}
|
|
||||||
b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
|
|
||||||
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn contains<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> bool {
|
|
||||||
for self.each |a| {
|
|
||||||
if *a == *x { return true; }
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
|
|
||||||
do foldl(self, 0) |count, value| {
|
|
||||||
if *value == *x {
|
|
||||||
*count + 1
|
|
||||||
} else {
|
|
||||||
*count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn position<A,IA:BaseIter<A>>(self: &IA, f: &fn(&A) -> bool)
|
|
||||||
-> Option<uint> {
|
|
||||||
let mut i = 0;
|
|
||||||
for self.each |a| {
|
|
||||||
if f(a) { return Some(i); }
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: 'rposition' would only make sense to provide with a bidirectional
|
|
||||||
// iter interface, such as would provide "reach" in addition to "each". As is,
|
|
||||||
// it would have to be implemented with foldr, which is too inefficient.
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn repeat(times: uint, blk: &fn() -> bool) {
|
|
||||||
let mut i = 0;
|
|
||||||
while i < times {
|
|
||||||
if !blk() { break }
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn min<A:Copy + Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
|
||||||
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
|
||||||
match a {
|
|
||||||
&Some(ref a_) if *a_ < *b => {
|
|
||||||
*(a)
|
|
||||||
}
|
|
||||||
_ => Some(*b)
|
|
||||||
}
|
|
||||||
} {
|
|
||||||
Some(val) => val,
|
|
||||||
None => fail!(~"min called on empty iterator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn max<A:Copy + Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
|
||||||
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
|
||||||
match a {
|
|
||||||
&Some(ref a_) if *a_ > *b => {
|
|
||||||
*(a)
|
|
||||||
}
|
|
||||||
_ => Some(*b)
|
|
||||||
}
|
|
||||||
} {
|
|
||||||
Some(val) => val,
|
|
||||||
None => fail!(~"max called on empty iterator")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn find<A:Copy,IA:BaseIter<A>>(self: &IA, f: &fn(&A) -> bool)
|
|
||||||
-> Option<A> {
|
|
||||||
for self.each |i| {
|
|
||||||
if f(i) { return Some(*i) }
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some functions for just building
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a sequence by calling a provided function with an argument
|
|
||||||
* function that pushes an element to the back of a sequence.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * builder - A function that will construct the sequence. It receives
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the sequence being constructed.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn build<A,B: Buildable<A>>(builder: &fn(push: &fn(A))) -> B {
|
|
||||||
Buildable::build_sized(4, builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a sequence by calling a provided function with an argument
|
|
||||||
* function that pushes an element to the back of the sequence.
|
|
||||||
* This version takes an initial size for the sequence.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * size - An option, maybe containing initial size of the sequence
|
|
||||||
* to reserve.
|
|
||||||
* * builder - A function that will construct the sequence. It receives
|
|
||||||
* as an argument a function that will push an element
|
|
||||||
* onto the sequence being constructed.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn build_sized_opt<A,B: Buildable<A>>(size: Option<uint>,
|
|
||||||
builder: &fn(push: &fn(A))) -> B {
|
|
||||||
Buildable::build_sized(size.get_or_default(4), builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions that combine iteration and building
|
|
||||||
|
|
||||||
/// Applies a function to each element of an iterable and returns the results
|
|
||||||
/// in a sequence built via `BU`. See also `map_to_vec`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: &fn(&T) -> U)
|
|
||||||
-> BU {
|
|
||||||
do build_sized_opt(v.size_hint()) |push| {
|
|
||||||
for v.each() |elem| {
|
|
||||||
push(f(elem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes a generic sequence from a function.
|
|
||||||
*
|
|
||||||
* Creates a generic sequence of size `n_elts` and initializes the elements
|
|
||||||
* to the value returned by the function `op`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT {
|
|
||||||
do Buildable::build_sized(n_elts) |push| {
|
|
||||||
let mut i: uint = 0u;
|
|
||||||
while i < n_elts { push(op(i)); i += 1u; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and initializes a generic sequence with some elements.
|
|
||||||
*
|
|
||||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
|
||||||
* to the value `t`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_elem<T:Copy,BT:Buildable<T>>(n_elts: uint, t: T) -> BT {
|
|
||||||
do Buildable::build_sized(n_elts) |push| {
|
|
||||||
let mut i: uint = 0;
|
|
||||||
while i < n_elts { push(t); i += 1; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Appends two generic sequences.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn append<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(lhs: &IT, rhs: &IT)
|
|
||||||
-> BT {
|
|
||||||
let size_opt = lhs.size_hint().chain_ref(
|
|
||||||
|sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
|
|
||||||
do build_sized_opt(size_opt) |push| {
|
|
||||||
for lhs.each |x| { push(*x); }
|
|
||||||
for rhs.each |x| { push(*x); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies a generic sequence, possibly converting it to a different
|
|
||||||
/// type of sequence.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn copy_seq<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(v: &IT) -> BT {
|
|
||||||
do build_sized_opt(v.size_hint()) |push| {
|
|
||||||
for v.each |x| { push(*x); }
|
|
||||||
}
|
|
||||||
}
|
|
1689
src/libcore/libc.rs
1689
src/libcore/libc.rs
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Logging
|
|
||||||
|
|
||||||
pub mod rustrt {
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
pub extern {
|
|
||||||
unsafe fn rust_log_console_on();
|
|
||||||
unsafe fn rust_log_console_off();
|
|
||||||
unsafe fn rust_log_str(level: u32,
|
|
||||||
string: *libc::c_char,
|
|
||||||
size: libc::size_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turns on logging to stdout globally
|
|
||||||
pub fn console_on() {
|
|
||||||
unsafe {
|
|
||||||
rustrt::rust_log_console_on();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns off logging to stdout globally
|
|
||||||
*
|
|
||||||
* Turns off the console unless the user has overridden the
|
|
||||||
* runtime environment's logging spec, e.g. by setting
|
|
||||||
* the RUST_LOG environment variable
|
|
||||||
*/
|
|
||||||
pub fn console_off() {
|
|
||||||
unsafe {
|
|
||||||
rustrt::rust_log_console_off();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
#[lang="log_type"]
|
|
||||||
pub fn log_type<T>(level: u32, object: &T) {
|
|
||||||
use cast::transmute;
|
|
||||||
use io;
|
|
||||||
use libc;
|
|
||||||
use repr;
|
|
||||||
use vec;
|
|
||||||
|
|
||||||
let bytes = do io::with_bytes_writer |writer| {
|
|
||||||
repr::write_repr(writer, object);
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
let len = bytes.len() as libc::size_t;
|
|
||||||
rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations on managed box types
|
|
||||||
|
|
||||||
use ptr;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
|
||||||
|
|
||||||
pub mod raw {
|
|
||||||
use intrinsic::TyDesc;
|
|
||||||
|
|
||||||
pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint;
|
|
||||||
pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
|
|
||||||
pub static RC_IMMORTAL : uint = 0x77777777;
|
|
||||||
|
|
||||||
pub struct BoxHeaderRepr {
|
|
||||||
ref_count: uint,
|
|
||||||
type_desc: *TyDesc,
|
|
||||||
prev: *BoxRepr,
|
|
||||||
next: *BoxRepr,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BoxRepr {
|
|
||||||
header: BoxHeaderRepr,
|
|
||||||
data: u8
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ptr_eq<T>(a: @T, b: @T) -> bool {
|
|
||||||
//! Determine if two shared boxes point to the same object
|
|
||||||
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mut_ptr_eq<T>(a: @mut T, b: @mut T) -> bool {
|
|
||||||
//! Determine if two mutable shared boxes point to the same object
|
|
||||||
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl<T:Eq> Eq for @T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &@T) -> bool { *(*self) == *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ne(&self, other: &@T) -> bool { *(*self) != *(*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl<T:Eq> Eq for @mut T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &@mut T) -> bool { *(*self) == *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ne(&self, other: &@mut T) -> bool { *(*self) != *(*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl<T:Ord> Ord for @T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn lt(&self, other: &@T) -> bool { *(*self) < *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn le(&self, other: &@T) -> bool { *(*self) <= *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ge(&self, other: &@T) -> bool { *(*self) >= *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn gt(&self, other: &@T) -> bool { *(*self) > *(*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl<T:Ord> Ord for @mut T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn lt(&self, other: &@mut T) -> bool { *(*self) < *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn le(&self, other: &@mut T) -> bool { *(*self) <= *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ge(&self, other: &@mut T) -> bool { *(*self) >= *(*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
let x = @3;
|
|
||||||
let y = @3;
|
|
||||||
assert!((ptr_eq::<int>(x, x)));
|
|
||||||
assert!((ptr_eq::<int>(y, y)));
|
|
||||||
assert!((!ptr_eq::<int>(x, y)));
|
|
||||||
assert!((!ptr_eq::<int>(y, x)));
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
|
|
||||||
Module for wrapping freezable data structures in managed boxes.
|
|
||||||
Normally freezable data structures require an unaliased reference,
|
|
||||||
such as `T` or `~T`, so that the compiler can track when they are
|
|
||||||
being mutated. The `managed<T>` type converts these static checks into
|
|
||||||
dynamic checks: your program will fail if you attempt to perform
|
|
||||||
mutation when the data structure should be immutable.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
use util::with;
|
|
||||||
use cast::transmute_immut;
|
|
||||||
|
|
||||||
enum Mode { ReadOnly, Mutable, Immutable }
|
|
||||||
|
|
||||||
struct Data<T> {
|
|
||||||
priv mut value: T,
|
|
||||||
priv mut mode: Mode
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Mut<T> = Data<T>;
|
|
||||||
|
|
||||||
pub fn Mut<T>(t: T) -> Mut<T> {
|
|
||||||
Data {value: t, mode: ReadOnly}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unwrap<T>(m: Mut<T>) -> T {
|
|
||||||
// Borrowck should prevent us from calling unwrap while the value
|
|
||||||
// is in use, as that would be a move from a borrowed value.
|
|
||||||
assert!((m.mode as uint) == (ReadOnly as uint));
|
|
||||||
let Data {value: value, mode: _} = m;
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
pub impl<T> Data<T> {
|
|
||||||
fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R {
|
|
||||||
match self.mode {
|
|
||||||
Immutable => fail!(~"currently immutable"),
|
|
||||||
ReadOnly | Mutable => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
do with(&mut self.mode, Mutable) {
|
|
||||||
op(&mut self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn borrow_const<R>(&self, op: &fn(t: &const T) -> R) -> R {
|
|
||||||
op(&const self.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn borrow_imm<R>(&self, op: &fn(t: &T) -> R) -> R {
|
|
||||||
match self.mode {
|
|
||||||
Mutable => fail!(~"currently mutable"),
|
|
||||||
ReadOnly | Immutable => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
do with(&mut self.mode, Immutable) {
|
|
||||||
op(unsafe{transmute_immut(&mut self.value)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn unwrap(self) -> T { unwrap(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
#[should_fail]
|
|
||||||
pub fn test_mut_in_imm() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_imm |_p| {
|
|
||||||
do m.borrow_mut |_q| {
|
|
||||||
// should not be permitted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
#[should_fail]
|
|
||||||
pub fn test_imm_in_mut() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_mut |_p| {
|
|
||||||
do m.borrow_imm |_q| {
|
|
||||||
// should not be permitted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_const_in_mut() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_mut |p| {
|
|
||||||
do m.borrow_const |q| {
|
|
||||||
assert!(*p == *q);
|
|
||||||
*p += 1;
|
|
||||||
assert!(*p == *q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_mut_in_const() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_const |p| {
|
|
||||||
do m.borrow_mut |q| {
|
|
||||||
assert!(*p == *q);
|
|
||||||
*q += 1;
|
|
||||||
assert!(*p == *q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_imm_in_const() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_const |p| {
|
|
||||||
do m.borrow_imm |q| {
|
|
||||||
assert!(*p == *q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_const_in_imm() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_imm |p| {
|
|
||||||
do m.borrow_const |q| {
|
|
||||||
assert!(*p == *q);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
#[should_fail]
|
|
||||||
pub fn test_mut_in_imm_in_const() {
|
|
||||||
let m = @Mut(1);
|
|
||||||
do m.borrow_const |_p| {
|
|
||||||
do m.borrow_imm |_q| {
|
|
||||||
do m.borrow_mut |_r| {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,648 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations and constants for `f32`
|
|
||||||
|
|
||||||
use cmath;
|
|
||||||
use libc::{c_float, c_int};
|
|
||||||
use num::NumCast;
|
|
||||||
use num::strconv;
|
|
||||||
use num;
|
|
||||||
use option::Option;
|
|
||||||
use unstable::intrinsics::floorf32;
|
|
||||||
use from_str;
|
|
||||||
use to_str;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp;
|
|
||||||
#[cfg(notest)] use ops;
|
|
||||||
|
|
||||||
pub use cmath::c_float_targ_consts::*;
|
|
||||||
|
|
||||||
macro_rules! delegate(
|
|
||||||
(
|
|
||||||
fn $name:ident(
|
|
||||||
$(
|
|
||||||
$arg:ident : $arg_ty:ty
|
|
||||||
),*
|
|
||||||
) -> $rv:ty = $bound_name:path
|
|
||||||
) => (
|
|
||||||
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
|
|
||||||
unsafe {
|
|
||||||
$bound_name($( $arg ),*)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
delegate!(fn acos(n: c_float) -> c_float = cmath::c_float_utils::acos)
|
|
||||||
delegate!(fn asin(n: c_float) -> c_float = cmath::c_float_utils::asin)
|
|
||||||
delegate!(fn atan(n: c_float) -> c_float = cmath::c_float_utils::atan)
|
|
||||||
delegate!(fn atan2(a: c_float, b: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::atan2)
|
|
||||||
delegate!(fn cbrt(n: c_float) -> c_float = cmath::c_float_utils::cbrt)
|
|
||||||
delegate!(fn ceil(n: c_float) -> c_float = cmath::c_float_utils::ceil)
|
|
||||||
delegate!(fn copysign(x: c_float, y: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::copysign)
|
|
||||||
delegate!(fn cos(n: c_float) -> c_float = cmath::c_float_utils::cos)
|
|
||||||
delegate!(fn cosh(n: c_float) -> c_float = cmath::c_float_utils::cosh)
|
|
||||||
delegate!(fn erf(n: c_float) -> c_float = cmath::c_float_utils::erf)
|
|
||||||
delegate!(fn erfc(n: c_float) -> c_float = cmath::c_float_utils::erfc)
|
|
||||||
delegate!(fn exp(n: c_float) -> c_float = cmath::c_float_utils::exp)
|
|
||||||
delegate!(fn expm1(n: c_float) -> c_float = cmath::c_float_utils::expm1)
|
|
||||||
delegate!(fn exp2(n: c_float) -> c_float = cmath::c_float_utils::exp2)
|
|
||||||
delegate!(fn abs(n: c_float) -> c_float = cmath::c_float_utils::abs)
|
|
||||||
delegate!(fn abs_sub(a: c_float, b: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::abs_sub)
|
|
||||||
delegate!(fn mul_add(a: c_float, b: c_float, c: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::mul_add)
|
|
||||||
delegate!(fn fmax(a: c_float, b: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::fmax)
|
|
||||||
delegate!(fn fmin(a: c_float, b: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::fmin)
|
|
||||||
delegate!(fn nextafter(x: c_float, y: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::nextafter)
|
|
||||||
delegate!(fn frexp(n: c_float, value: &mut c_int) -> c_float =
|
|
||||||
cmath::c_float_utils::frexp)
|
|
||||||
delegate!(fn hypot(x: c_float, y: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::hypot)
|
|
||||||
delegate!(fn ldexp(x: c_float, n: c_int) -> c_float =
|
|
||||||
cmath::c_float_utils::ldexp)
|
|
||||||
delegate!(fn lgamma(n: c_float, sign: &mut c_int) -> c_float =
|
|
||||||
cmath::c_float_utils::lgamma)
|
|
||||||
delegate!(fn ln(n: c_float) -> c_float = cmath::c_float_utils::ln)
|
|
||||||
delegate!(fn log_radix(n: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::log_radix)
|
|
||||||
delegate!(fn ln1p(n: c_float) -> c_float = cmath::c_float_utils::ln1p)
|
|
||||||
delegate!(fn log10(n: c_float) -> c_float = cmath::c_float_utils::log10)
|
|
||||||
delegate!(fn log2(n: c_float) -> c_float = cmath::c_float_utils::log2)
|
|
||||||
delegate!(fn ilog_radix(n: c_float) -> c_int =
|
|
||||||
cmath::c_float_utils::ilog_radix)
|
|
||||||
delegate!(fn modf(n: c_float, iptr: &mut c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::modf)
|
|
||||||
delegate!(fn pow(n: c_float, e: c_float) -> c_float =
|
|
||||||
cmath::c_float_utils::pow)
|
|
||||||
delegate!(fn round(n: c_float) -> c_float = cmath::c_float_utils::round)
|
|
||||||
delegate!(fn ldexp_radix(n: c_float, i: c_int) -> c_float =
|
|
||||||
cmath::c_float_utils::ldexp_radix)
|
|
||||||
delegate!(fn sin(n: c_float) -> c_float = cmath::c_float_utils::sin)
|
|
||||||
delegate!(fn sinh(n: c_float) -> c_float = cmath::c_float_utils::sinh)
|
|
||||||
delegate!(fn sqrt(n: c_float) -> c_float = cmath::c_float_utils::sqrt)
|
|
||||||
delegate!(fn tan(n: c_float) -> c_float = cmath::c_float_utils::tan)
|
|
||||||
delegate!(fn tanh(n: c_float) -> c_float = cmath::c_float_utils::tanh)
|
|
||||||
delegate!(fn tgamma(n: c_float) -> c_float = cmath::c_float_utils::tgamma)
|
|
||||||
delegate!(fn trunc(n: c_float) -> c_float = cmath::c_float_utils::trunc)
|
|
||||||
|
|
||||||
// These are not defined inside consts:: for consistency with
|
|
||||||
// the integer types
|
|
||||||
|
|
||||||
pub static NaN: f32 = 0.0_f32/0.0_f32;
|
|
||||||
|
|
||||||
pub static infinity: f32 = 1.0_f32/0.0_f32;
|
|
||||||
|
|
||||||
pub static neg_infinity: f32 = -1.0_f32/0.0_f32;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_NaN(f: f32) -> bool { f != f }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn add(x: f32, y: f32) -> f32 { return x + y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sub(x: f32, y: f32) -> f32 { return x - y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mul(x: f32, y: f32) -> f32 { return x * y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn div(x: f32, y: f32) -> f32 { return x / y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn rem(x: f32, y: f32) -> f32 { return x % y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lt(x: f32, y: f32) -> bool { return x < y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn le(x: f32, y: f32) -> bool { return x <= y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn eq(x: f32, y: f32) -> bool { return x == y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ne(x: f32, y: f32) -> bool { return x != y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ge(x: f32, y: f32) -> bool { return x >= y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn gt(x: f32, y: f32) -> bool { return x > y; }
|
|
||||||
|
|
||||||
/// Returns `x` rounded down
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn floor(x: f32) -> f32 { unsafe { floorf32(x) } }
|
|
||||||
|
|
||||||
// FIXME (#1999): replace the predicates below with llvm intrinsics or
|
|
||||||
// calls to the libmath macros in the rust runtime for performance.
|
|
||||||
|
|
||||||
/// Returns true if `x` is a positive number, including +0.0f320 and +Infinity
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_positive(x: f32) -> bool {
|
|
||||||
x > 0.0f32 || (1.0f32/x) == infinity
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x` is a negative number, including -0.0f320 and -Infinity
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_negative(x: f32) -> bool {
|
|
||||||
x < 0.0f32 || (1.0f32/x) == neg_infinity
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if `x` is a negative number, including -0.0f320 and -Infinity
|
|
||||||
*
|
|
||||||
* This is the same as `f32::is_negative`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonpositive(x: f32) -> bool {
|
|
||||||
return x < 0.0f32 || (1.0f32/x) == neg_infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if `x` is a positive number, including +0.0f320 and +Infinity
|
|
||||||
*
|
|
||||||
* This is the same as `f32::is_positive`.)
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonnegative(x: f32) -> bool {
|
|
||||||
return x > 0.0f32 || (1.0f32/x) == infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x` is a zero number (positive or negative zero)
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_zero(x: f32) -> bool {
|
|
||||||
return x == 0.0f32 || x == -0.0f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x`is an infinite number
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_infinite(x: f32) -> bool {
|
|
||||||
return x == infinity || x == neg_infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x`is a finite number
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_finite(x: f32) -> bool {
|
|
||||||
return !(is_NaN(x) || is_infinite(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify.
|
|
||||||
|
|
||||||
/* Module: consts */
|
|
||||||
pub mod consts {
|
|
||||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
|
||||||
// staticants from cmath.
|
|
||||||
/// Archimedes' staticant
|
|
||||||
pub static pi: f32 = 3.14159265358979323846264338327950288_f32;
|
|
||||||
|
|
||||||
/// pi/2.0
|
|
||||||
pub static frac_pi_2: f32 = 1.57079632679489661923132169163975144_f32;
|
|
||||||
|
|
||||||
/// pi/4.0
|
|
||||||
pub static frac_pi_4: f32 = 0.785398163397448309615660845819875721_f32;
|
|
||||||
|
|
||||||
/// 1.0/pi
|
|
||||||
pub static frac_1_pi: f32 = 0.318309886183790671537767526745028724_f32;
|
|
||||||
|
|
||||||
/// 2.0/pi
|
|
||||||
pub static frac_2_pi: f32 = 0.636619772367581343075535053490057448_f32;
|
|
||||||
|
|
||||||
/// 2.0/sqrt(pi)
|
|
||||||
pub static frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517_f32;
|
|
||||||
|
|
||||||
/// sqrt(2.0)
|
|
||||||
pub static sqrt2: f32 = 1.41421356237309504880168872420969808_f32;
|
|
||||||
|
|
||||||
/// 1.0/sqrt(2.0)
|
|
||||||
pub static frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039_f32;
|
|
||||||
|
|
||||||
/// Euler's number
|
|
||||||
pub static e: f32 = 2.71828182845904523536028747135266250_f32;
|
|
||||||
|
|
||||||
/// log2(e)
|
|
||||||
pub static log2_e: f32 = 1.44269504088896340735992468100189214_f32;
|
|
||||||
|
|
||||||
/// log10(e)
|
|
||||||
pub static log10_e: f32 = 0.434294481903251827651128918916605082_f32;
|
|
||||||
|
|
||||||
/// ln(2.0)
|
|
||||||
pub static ln_2: f32 = 0.693147180559945309417232121458176568_f32;
|
|
||||||
|
|
||||||
/// ln(10.0)
|
|
||||||
pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn signbit(x: f32) -> int {
|
|
||||||
if is_negative(x) { return 1; } else { return 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn logarithm(n: f32, b: f32) -> f32 {
|
|
||||||
return log2(n) / log2(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl cmp::Eq for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &f32) -> bool { (*self) == (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ne(&self, other: &f32) -> bool { (*self) != (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl cmp::Ord for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn lt(&self, other: &f32) -> bool { (*self) < (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn le(&self, other: &f32) -> bool { (*self) <= (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ge(&self, other: &f32) -> bool { (*self) >= (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn gt(&self, other: &f32) -> bool { (*self) > (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Zero for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn zero() -> f32 { 0.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::One for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn one() -> f32 { 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NumCast for f32 {
|
|
||||||
/**
|
|
||||||
* Cast `n` to an `f32`
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
fn from<N:NumCast>(n: N) -> f32 { n.to_f32() }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
|
||||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
|
||||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
|
||||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
|
||||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
|
||||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
|
||||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
|
||||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
|
||||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_f32(&self) -> f32 { *self }
|
|
||||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
|
||||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Add<f32,f32> for f32 {
|
|
||||||
fn add(&self, other: &f32) -> f32 { *self + *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Sub<f32,f32> for f32 {
|
|
||||||
fn sub(&self, other: &f32) -> f32 { *self - *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Mul<f32,f32> for f32 {
|
|
||||||
fn mul(&self, other: &f32) -> f32 { *self * *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Div<f32,f32> for f32 {
|
|
||||||
fn div(&self, other: &f32) -> f32 { *self / *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Modulo<f32,f32> for f32 {
|
|
||||||
fn modulo(&self, other: &f32) -> f32 { *self % *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Neg<f32> for f32 {
|
|
||||||
fn neg(&self) -> f32 { -*self }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Round for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn round(&self, mode: num::RoundMode) -> f32 {
|
|
||||||
match mode {
|
|
||||||
num::RoundDown => floor(*self),
|
|
||||||
num::RoundUp => ceil(*self),
|
|
||||||
num::RoundToZero if is_negative(*self) => ceil(*self),
|
|
||||||
num::RoundToZero => floor(*self),
|
|
||||||
num::RoundFromZero if is_negative(*self) => floor(*self),
|
|
||||||
num::RoundFromZero => ceil(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn floor(&self) -> f32 { floor(*self) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ceil(&self) -> f32 { ceil(*self) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn fract(&self) -> f32 {
|
|
||||||
if is_negative(*self) {
|
|
||||||
(*self) - ceil(*self)
|
|
||||||
} else {
|
|
||||||
(*self) - floor(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Section: String Conversions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str(num: f32) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in hexadecimal format
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_hex(num: f32) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*
|
|
||||||
* # Failure
|
|
||||||
*
|
|
||||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
|
||||||
* possible misinterpretation of the result at higher bases. If those values
|
|
||||||
* are expected, use `to_str_radix_special()` instead.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
|
||||||
let (r, special) = strconv::to_str_common(
|
|
||||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
if special { fail!(~"number has a special value, \
|
|
||||||
try to_str_radix_special() if those are expected") }
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix, and a flag indicating
|
|
||||||
* whether it's a special value
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
|
||||||
strconv::to_str_common(&num, rdx, true,
|
|
||||||
strconv::SignNeg, strconv::DigAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with exactly the number of
|
|
||||||
* provided significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_exact(num: f32, dig: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with a maximum number of
|
|
||||||
* significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_digits(num: f32, dig: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
impl to_str::ToStr for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::ToStrRadix for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str_radix(&self, rdx: uint) -> ~str {
|
|
||||||
to_str_radix(*self, rdx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 10 to a float.
|
|
||||||
* Accepts a optional decimal exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * '3.14'
|
|
||||||
* * '+3.14', equivalent to '3.14'
|
|
||||||
* * '-3.14'
|
|
||||||
* * '2.5E10', or equivalently, '2.5e10'
|
|
||||||
* * '2.5E-10'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * '5.'
|
|
||||||
* * '.5', or, equivalently, '0.5'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str(num: &str) -> Option<f32> {
|
|
||||||
strconv::from_str_common(num, 10u, true, true, true,
|
|
||||||
strconv::ExpDec, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 16 to a float.
|
|
||||||
* Accepts a optional binary exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * 'a4.fe'
|
|
||||||
* * '+a4.fe', equivalent to 'a4.fe'
|
|
||||||
* * '-a4.fe'
|
|
||||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
|
||||||
* * '2b.aP-128'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * 'c.'
|
|
||||||
* * '.c', or, equivalently, '0.c'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_hex(num: &str) -> Option<f32> {
|
|
||||||
strconv::from_str_common(num, 16u, true, true, true,
|
|
||||||
strconv::ExpBin, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in an given base to a float.
|
|
||||||
*
|
|
||||||
* Due to possible conflicts, this function does **not** accept
|
|
||||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
|
||||||
* does it recognize exponents of any kind.
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
|
|
||||||
strconv::from_str_common(num, rdx, true, true, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl from_str::FromStr for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str(val: &str) -> Option<f32> { from_str(val) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::FromStrRadix for f32 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
|
|
||||||
from_str_radix(val, rdx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_num() {
|
|
||||||
let ten: f32 = num::cast(10);
|
|
||||||
let two: f32 = num::cast(2);
|
|
||||||
|
|
||||||
assert!((ten.add(&two) == num::cast(12)));
|
|
||||||
assert!((ten.sub(&two) == num::cast(8)));
|
|
||||||
assert!((ten.mul(&two) == num::cast(20)));
|
|
||||||
assert!((ten.div(&two) == num::cast(5)));
|
|
||||||
assert!((ten.modulo(&two) == num::cast(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_numcast() {
|
|
||||||
assert!((20u == 20f32.to_uint()));
|
|
||||||
assert!((20u8 == 20f32.to_u8()));
|
|
||||||
assert!((20u16 == 20f32.to_u16()));
|
|
||||||
assert!((20u32 == 20f32.to_u32()));
|
|
||||||
assert!((20u64 == 20f32.to_u64()));
|
|
||||||
assert!((20i == 20f32.to_int()));
|
|
||||||
assert!((20i8 == 20f32.to_i8()));
|
|
||||||
assert!((20i16 == 20f32.to_i16()));
|
|
||||||
assert!((20i32 == 20f32.to_i32()));
|
|
||||||
assert!((20i64 == 20f32.to_i64()));
|
|
||||||
assert!((20f == 20f32.to_float()));
|
|
||||||
assert!((20f32 == 20f32.to_f32()));
|
|
||||||
assert!((20f64 == 20f32.to_f64()));
|
|
||||||
|
|
||||||
assert!((20f32 == NumCast::from(20u)));
|
|
||||||
assert!((20f32 == NumCast::from(20u8)));
|
|
||||||
assert!((20f32 == NumCast::from(20u16)));
|
|
||||||
assert!((20f32 == NumCast::from(20u32)));
|
|
||||||
assert!((20f32 == NumCast::from(20u64)));
|
|
||||||
assert!((20f32 == NumCast::from(20i)));
|
|
||||||
assert!((20f32 == NumCast::from(20i8)));
|
|
||||||
assert!((20f32 == NumCast::from(20i16)));
|
|
||||||
assert!((20f32 == NumCast::from(20i32)));
|
|
||||||
assert!((20f32 == NumCast::from(20i64)));
|
|
||||||
assert!((20f32 == NumCast::from(20f)));
|
|
||||||
assert!((20f32 == NumCast::from(20f32)));
|
|
||||||
assert!((20f32 == NumCast::from(20f64)));
|
|
||||||
|
|
||||||
assert!((20f32 == num::cast(20u)));
|
|
||||||
assert!((20f32 == num::cast(20u8)));
|
|
||||||
assert!((20f32 == num::cast(20u16)));
|
|
||||||
assert!((20f32 == num::cast(20u32)));
|
|
||||||
assert!((20f32 == num::cast(20u64)));
|
|
||||||
assert!((20f32 == num::cast(20i)));
|
|
||||||
assert!((20f32 == num::cast(20i8)));
|
|
||||||
assert!((20f32 == num::cast(20i16)));
|
|
||||||
assert!((20f32 == num::cast(20i32)));
|
|
||||||
assert!((20f32 == num::cast(20i64)));
|
|
||||||
assert!((20f32 == num::cast(20f)));
|
|
||||||
assert!((20f32 == num::cast(20f32)));
|
|
||||||
assert!((20f32 == num::cast(20f64)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
||||||
//
|
|
@ -1,670 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations and constants for `f64`
|
|
||||||
|
|
||||||
use cmath;
|
|
||||||
use libc::{c_double, c_int};
|
|
||||||
use num::NumCast;
|
|
||||||
use num::strconv;
|
|
||||||
use num;
|
|
||||||
use option::Option;
|
|
||||||
use unstable::intrinsics::floorf64;
|
|
||||||
use to_str;
|
|
||||||
use from_str;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp;
|
|
||||||
#[cfg(notest)] use ops;
|
|
||||||
|
|
||||||
pub use cmath::c_double_targ_consts::*;
|
|
||||||
pub use cmp::{min, max};
|
|
||||||
|
|
||||||
macro_rules! delegate(
|
|
||||||
(
|
|
||||||
fn $name:ident(
|
|
||||||
$(
|
|
||||||
$arg:ident : $arg_ty:ty
|
|
||||||
),*
|
|
||||||
) -> $rv:ty = $bound_name:path
|
|
||||||
) => (
|
|
||||||
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
|
|
||||||
unsafe {
|
|
||||||
$bound_name($( $arg ),*)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
delegate!(fn acos(n: c_double) -> c_double = cmath::c_double_utils::acos)
|
|
||||||
delegate!(fn asin(n: c_double) -> c_double = cmath::c_double_utils::asin)
|
|
||||||
delegate!(fn atan(n: c_double) -> c_double = cmath::c_double_utils::atan)
|
|
||||||
delegate!(fn atan2(a: c_double, b: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::atan2)
|
|
||||||
delegate!(fn cbrt(n: c_double) -> c_double = cmath::c_double_utils::cbrt)
|
|
||||||
delegate!(fn ceil(n: c_double) -> c_double = cmath::c_double_utils::ceil)
|
|
||||||
delegate!(fn copysign(x: c_double, y: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::copysign)
|
|
||||||
delegate!(fn cos(n: c_double) -> c_double = cmath::c_double_utils::cos)
|
|
||||||
delegate!(fn cosh(n: c_double) -> c_double = cmath::c_double_utils::cosh)
|
|
||||||
delegate!(fn erf(n: c_double) -> c_double = cmath::c_double_utils::erf)
|
|
||||||
delegate!(fn erfc(n: c_double) -> c_double = cmath::c_double_utils::erfc)
|
|
||||||
delegate!(fn exp(n: c_double) -> c_double = cmath::c_double_utils::exp)
|
|
||||||
delegate!(fn expm1(n: c_double) -> c_double = cmath::c_double_utils::expm1)
|
|
||||||
delegate!(fn exp2(n: c_double) -> c_double = cmath::c_double_utils::exp2)
|
|
||||||
delegate!(fn abs(n: c_double) -> c_double = cmath::c_double_utils::abs)
|
|
||||||
delegate!(fn abs_sub(a: c_double, b: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::abs_sub)
|
|
||||||
delegate!(fn mul_add(a: c_double, b: c_double, c: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::mul_add)
|
|
||||||
delegate!(fn fmax(a: c_double, b: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::fmax)
|
|
||||||
delegate!(fn fmin(a: c_double, b: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::fmin)
|
|
||||||
delegate!(fn nextafter(x: c_double, y: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::nextafter)
|
|
||||||
delegate!(fn frexp(n: c_double, value: &mut c_int) -> c_double =
|
|
||||||
cmath::c_double_utils::frexp)
|
|
||||||
delegate!(fn hypot(x: c_double, y: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::hypot)
|
|
||||||
delegate!(fn ldexp(x: c_double, n: c_int) -> c_double =
|
|
||||||
cmath::c_double_utils::ldexp)
|
|
||||||
delegate!(fn lgamma(n: c_double, sign: &mut c_int) -> c_double =
|
|
||||||
cmath::c_double_utils::lgamma)
|
|
||||||
delegate!(fn ln(n: c_double) -> c_double = cmath::c_double_utils::ln)
|
|
||||||
delegate!(fn log_radix(n: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::log_radix)
|
|
||||||
delegate!(fn ln1p(n: c_double) -> c_double = cmath::c_double_utils::ln1p)
|
|
||||||
delegate!(fn log10(n: c_double) -> c_double = cmath::c_double_utils::log10)
|
|
||||||
delegate!(fn log2(n: c_double) -> c_double = cmath::c_double_utils::log2)
|
|
||||||
delegate!(fn ilog_radix(n: c_double) -> c_int =
|
|
||||||
cmath::c_double_utils::ilog_radix)
|
|
||||||
delegate!(fn modf(n: c_double, iptr: &mut c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::modf)
|
|
||||||
delegate!(fn pow(n: c_double, e: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::pow)
|
|
||||||
delegate!(fn round(n: c_double) -> c_double = cmath::c_double_utils::round)
|
|
||||||
delegate!(fn ldexp_radix(n: c_double, i: c_int) -> c_double =
|
|
||||||
cmath::c_double_utils::ldexp_radix)
|
|
||||||
delegate!(fn sin(n: c_double) -> c_double = cmath::c_double_utils::sin)
|
|
||||||
delegate!(fn sinh(n: c_double) -> c_double = cmath::c_double_utils::sinh)
|
|
||||||
delegate!(fn sqrt(n: c_double) -> c_double = cmath::c_double_utils::sqrt)
|
|
||||||
delegate!(fn tan(n: c_double) -> c_double = cmath::c_double_utils::tan)
|
|
||||||
delegate!(fn tanh(n: c_double) -> c_double = cmath::c_double_utils::tanh)
|
|
||||||
delegate!(fn tgamma(n: c_double) -> c_double = cmath::c_double_utils::tgamma)
|
|
||||||
delegate!(fn trunc(n: c_double) -> c_double = cmath::c_double_utils::trunc)
|
|
||||||
delegate!(fn j0(n: c_double) -> c_double = cmath::c_double_utils::j0)
|
|
||||||
delegate!(fn j1(n: c_double) -> c_double = cmath::c_double_utils::j1)
|
|
||||||
delegate!(fn jn(i: c_int, n: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::jn)
|
|
||||||
delegate!(fn y0(n: c_double) -> c_double = cmath::c_double_utils::y0)
|
|
||||||
delegate!(fn y1(n: c_double) -> c_double = cmath::c_double_utils::y1)
|
|
||||||
delegate!(fn yn(i: c_int, n: c_double) -> c_double =
|
|
||||||
cmath::c_double_utils::yn)
|
|
||||||
|
|
||||||
// FIXME (#1433): obtain these in a different way
|
|
||||||
|
|
||||||
// These are not defined inside consts:: for consistency with
|
|
||||||
// the integer types
|
|
||||||
|
|
||||||
pub static radix: uint = 2u;
|
|
||||||
|
|
||||||
pub static mantissa_digits: uint = 53u;
|
|
||||||
pub static digits: uint = 15u;
|
|
||||||
|
|
||||||
pub static epsilon: f64 = 2.2204460492503131e-16_f64;
|
|
||||||
|
|
||||||
pub static min_value: f64 = 2.2250738585072014e-308_f64;
|
|
||||||
pub static max_value: f64 = 1.7976931348623157e+308_f64;
|
|
||||||
|
|
||||||
pub static min_exp: int = -1021;
|
|
||||||
pub static max_exp: int = 1024;
|
|
||||||
|
|
||||||
pub static min_10_exp: int = -307;
|
|
||||||
pub static max_10_exp: int = 308;
|
|
||||||
|
|
||||||
pub static NaN: f64 = 0.0_f64/0.0_f64;
|
|
||||||
|
|
||||||
pub static infinity: f64 = 1.0_f64/0.0_f64;
|
|
||||||
|
|
||||||
pub static neg_infinity: f64 = -1.0_f64/0.0_f64;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_NaN(f: f64) -> bool { f != f }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn add(x: f64, y: f64) -> f64 { return x + y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sub(x: f64, y: f64) -> f64 { return x - y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mul(x: f64, y: f64) -> f64 { return x * y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn div(x: f64, y: f64) -> f64 { return x / y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn rem(x: f64, y: f64) -> f64 { return x % y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lt(x: f64, y: f64) -> bool { return x < y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn le(x: f64, y: f64) -> bool { return x <= y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn eq(x: f64, y: f64) -> bool { return x == y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ne(x: f64, y: f64) -> bool { return x != y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ge(x: f64, y: f64) -> bool { return x >= y; }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn gt(x: f64, y: f64) -> bool { return x > y; }
|
|
||||||
|
|
||||||
/// Returns true if `x` is a positive number, including +0.0f640 and +Infinity
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_positive(x: f64) -> bool
|
|
||||||
{ return x > 0.0f64 || (1.0f64/x) == infinity; }
|
|
||||||
|
|
||||||
/// Returns true if `x` is a negative number, including -0.0f640 and -Infinity
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_negative(x: f64) -> bool
|
|
||||||
{ return x < 0.0f64 || (1.0f64/x) == neg_infinity; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if `x` is a negative number, including -0.0f640 and -Infinity
|
|
||||||
*
|
|
||||||
* This is the same as `f64::is_negative`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonpositive(x: f64) -> bool {
|
|
||||||
return x < 0.0f64 || (1.0f64/x) == neg_infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if `x` is a positive number, including +0.0f640 and +Infinity
|
|
||||||
*
|
|
||||||
* This is the same as `f64::positive`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonnegative(x: f64) -> bool {
|
|
||||||
return x > 0.0f64 || (1.0f64/x) == infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x` is a zero number (positive or negative zero)
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_zero(x: f64) -> bool {
|
|
||||||
return x == 0.0f64 || x == -0.0f64;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x`is an infinite number
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_infinite(x: f64) -> bool {
|
|
||||||
return x == infinity || x == neg_infinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `x` is a finite number
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_finite(x: f64) -> bool {
|
|
||||||
return !(is_NaN(x) || is_infinite(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `x` rounded down
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn floor(x: f64) -> f64 { unsafe { floorf64(x) } }
|
|
||||||
|
|
||||||
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify
|
|
||||||
|
|
||||||
/* Module: consts */
|
|
||||||
pub mod consts {
|
|
||||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
|
||||||
// constants from cmath.
|
|
||||||
/// Archimedes' constant
|
|
||||||
pub static pi: f64 = 3.14159265358979323846264338327950288_f64;
|
|
||||||
|
|
||||||
/// pi/2.0
|
|
||||||
pub static frac_pi_2: f64 = 1.57079632679489661923132169163975144_f64;
|
|
||||||
|
|
||||||
/// pi/4.0
|
|
||||||
pub static frac_pi_4: f64 = 0.785398163397448309615660845819875721_f64;
|
|
||||||
|
|
||||||
/// 1.0/pi
|
|
||||||
pub static frac_1_pi: f64 = 0.318309886183790671537767526745028724_f64;
|
|
||||||
|
|
||||||
/// 2.0/pi
|
|
||||||
pub static frac_2_pi: f64 = 0.636619772367581343075535053490057448_f64;
|
|
||||||
|
|
||||||
/// 2.0/sqrt(pi)
|
|
||||||
pub static frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517_f64;
|
|
||||||
|
|
||||||
/// sqrt(2.0)
|
|
||||||
pub static sqrt2: f64 = 1.41421356237309504880168872420969808_f64;
|
|
||||||
|
|
||||||
/// 1.0/sqrt(2.0)
|
|
||||||
pub static frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039_f64;
|
|
||||||
|
|
||||||
/// Euler's number
|
|
||||||
pub static e: f64 = 2.71828182845904523536028747135266250_f64;
|
|
||||||
|
|
||||||
/// log2(e)
|
|
||||||
pub static log2_e: f64 = 1.44269504088896340735992468100189214_f64;
|
|
||||||
|
|
||||||
/// log10(e)
|
|
||||||
pub static log10_e: f64 = 0.434294481903251827651128918916605082_f64;
|
|
||||||
|
|
||||||
/// ln(2.0)
|
|
||||||
pub static ln_2: f64 = 0.693147180559945309417232121458176568_f64;
|
|
||||||
|
|
||||||
/// ln(10.0)
|
|
||||||
pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn signbit(x: f64) -> int {
|
|
||||||
if is_negative(x) { return 1; } else { return 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn logarithm(n: f64, b: f64) -> f64 {
|
|
||||||
return log2(n) / log2(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl cmp::Eq for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &f64) -> bool { (*self) == (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ne(&self, other: &f64) -> bool { (*self) != (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl cmp::Ord for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn lt(&self, other: &f64) -> bool { (*self) < (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn le(&self, other: &f64) -> bool { (*self) <= (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ge(&self, other: &f64) -> bool { (*self) >= (*other) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn gt(&self, other: &f64) -> bool { (*self) > (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NumCast for f64 {
|
|
||||||
/**
|
|
||||||
* Cast `n` to an `f64`
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
fn from<N:NumCast>(n: N) -> f64 { n.to_f64() }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
|
||||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
|
||||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
|
||||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
|
||||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
|
||||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
|
||||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
|
||||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
|
||||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
|
||||||
#[inline(always)] fn to_f64(&self) -> f64 { *self }
|
|
||||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Zero for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn zero() -> f64 { 0.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::One for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn one() -> f64 { 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Add<f64,f64> for f64 {
|
|
||||||
fn add(&self, other: &f64) -> f64 { *self + *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Sub<f64,f64> for f64 {
|
|
||||||
fn sub(&self, other: &f64) -> f64 { *self - *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Mul<f64,f64> for f64 {
|
|
||||||
fn mul(&self, other: &f64) -> f64 { *self * *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Div<f64,f64> for f64 {
|
|
||||||
fn div(&self, other: &f64) -> f64 { *self / *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Modulo<f64,f64> for f64 {
|
|
||||||
fn modulo(&self, other: &f64) -> f64 { *self % *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Neg<f64> for f64 {
|
|
||||||
fn neg(&self) -> f64 { -*self }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Round for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn round(&self, mode: num::RoundMode) -> f64 {
|
|
||||||
match mode {
|
|
||||||
num::RoundDown => floor(*self),
|
|
||||||
num::RoundUp => ceil(*self),
|
|
||||||
num::RoundToZero if is_negative(*self) => ceil(*self),
|
|
||||||
num::RoundToZero => floor(*self),
|
|
||||||
num::RoundFromZero if is_negative(*self) => floor(*self),
|
|
||||||
num::RoundFromZero => ceil(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn floor(&self) -> f64 { floor(*self) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ceil(&self) -> f64 { ceil(*self) }
|
|
||||||
#[inline(always)]
|
|
||||||
fn fract(&self) -> f64 {
|
|
||||||
if is_negative(*self) {
|
|
||||||
(*self) - ceil(*self)
|
|
||||||
} else {
|
|
||||||
(*self) - floor(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Section: String Conversions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str(num: f64) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in hexadecimal format
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_hex(num: f64) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*
|
|
||||||
* # Failure
|
|
||||||
*
|
|
||||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
|
||||||
* possible misinterpretation of the result at higher bases. If those values
|
|
||||||
* are expected, use `to_str_radix_special()` instead.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
|
||||||
let (r, special) = strconv::to_str_common(
|
|
||||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
if special { fail!(~"number has a special value, \
|
|
||||||
try to_str_radix_special() if those are expected") }
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix, and a flag indicating
|
|
||||||
* whether it's a special value
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
|
||||||
strconv::to_str_common(&num, rdx, true,
|
|
||||||
strconv::SignNeg, strconv::DigAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with exactly the number of
|
|
||||||
* provided significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_exact(num: f64, dig: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with a maximum number of
|
|
||||||
* significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_digits(num: f64, dig: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
impl to_str::ToStr for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::ToStrRadix for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str_radix(&self, rdx: uint) -> ~str {
|
|
||||||
to_str_radix(*self, rdx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 10 to a float.
|
|
||||||
* Accepts a optional decimal exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * '3.14'
|
|
||||||
* * '+3.14', equivalent to '3.14'
|
|
||||||
* * '-3.14'
|
|
||||||
* * '2.5E10', or equivalently, '2.5e10'
|
|
||||||
* * '2.5E-10'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * '5.'
|
|
||||||
* * '.5', or, equivalently, '0.5'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str(num: &str) -> Option<f64> {
|
|
||||||
strconv::from_str_common(num, 10u, true, true, true,
|
|
||||||
strconv::ExpDec, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 16 to a float.
|
|
||||||
* Accepts a optional binary exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * 'a4.fe'
|
|
||||||
* * '+a4.fe', equivalent to 'a4.fe'
|
|
||||||
* * '-a4.fe'
|
|
||||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
|
||||||
* * '2b.aP-128'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * 'c.'
|
|
||||||
* * '.c', or, equivalently, '0.c'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_hex(num: &str) -> Option<f64> {
|
|
||||||
strconv::from_str_common(num, 16u, true, true, true,
|
|
||||||
strconv::ExpBin, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in an given base to a float.
|
|
||||||
*
|
|
||||||
* Due to possible conflicts, this function does **not** accept
|
|
||||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
|
||||||
* does it recognize exponents of any kind.
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
|
|
||||||
strconv::from_str_common(num, rdx, true, true, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl from_str::FromStr for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str(val: &str) -> Option<f64> { from_str(val) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::FromStrRadix for f64 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
|
|
||||||
from_str_radix(val, rdx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_num() {
|
|
||||||
let ten: f64 = num::cast(10);
|
|
||||||
let two: f64 = num::cast(2);
|
|
||||||
|
|
||||||
assert!((ten.add(&two) == num::cast(12)));
|
|
||||||
assert!((ten.sub(&two) == num::cast(8)));
|
|
||||||
assert!((ten.mul(&two) == num::cast(20)));
|
|
||||||
assert!((ten.div(&two) == num::cast(5)));
|
|
||||||
assert!((ten.modulo(&two) == num::cast(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_numcast() {
|
|
||||||
assert!((20u == 20f64.to_uint()));
|
|
||||||
assert!((20u8 == 20f64.to_u8()));
|
|
||||||
assert!((20u16 == 20f64.to_u16()));
|
|
||||||
assert!((20u32 == 20f64.to_u32()));
|
|
||||||
assert!((20u64 == 20f64.to_u64()));
|
|
||||||
assert!((20i == 20f64.to_int()));
|
|
||||||
assert!((20i8 == 20f64.to_i8()));
|
|
||||||
assert!((20i16 == 20f64.to_i16()));
|
|
||||||
assert!((20i32 == 20f64.to_i32()));
|
|
||||||
assert!((20i64 == 20f64.to_i64()));
|
|
||||||
assert!((20f == 20f64.to_float()));
|
|
||||||
assert!((20f32 == 20f64.to_f32()));
|
|
||||||
assert!((20f64 == 20f64.to_f64()));
|
|
||||||
|
|
||||||
assert!((20f64 == NumCast::from(20u)));
|
|
||||||
assert!((20f64 == NumCast::from(20u8)));
|
|
||||||
assert!((20f64 == NumCast::from(20u16)));
|
|
||||||
assert!((20f64 == NumCast::from(20u32)));
|
|
||||||
assert!((20f64 == NumCast::from(20u64)));
|
|
||||||
assert!((20f64 == NumCast::from(20i)));
|
|
||||||
assert!((20f64 == NumCast::from(20i8)));
|
|
||||||
assert!((20f64 == NumCast::from(20i16)));
|
|
||||||
assert!((20f64 == NumCast::from(20i32)));
|
|
||||||
assert!((20f64 == NumCast::from(20i64)));
|
|
||||||
assert!((20f64 == NumCast::from(20f)));
|
|
||||||
assert!((20f64 == NumCast::from(20f32)));
|
|
||||||
assert!((20f64 == NumCast::from(20f64)));
|
|
||||||
|
|
||||||
assert!((20f64 == num::cast(20u)));
|
|
||||||
assert!((20f64 == num::cast(20u8)));
|
|
||||||
assert!((20f64 == num::cast(20u16)));
|
|
||||||
assert!((20f64 == num::cast(20u32)));
|
|
||||||
assert!((20f64 == num::cast(20u64)));
|
|
||||||
assert!((20f64 == num::cast(20i)));
|
|
||||||
assert!((20f64 == num::cast(20i8)));
|
|
||||||
assert!((20f64 == num::cast(20i16)));
|
|
||||||
assert!((20f64 == num::cast(20i32)));
|
|
||||||
assert!((20f64 == num::cast(20i64)));
|
|
||||||
assert!((20f64 == num::cast(20f)));
|
|
||||||
assert!((20f64 == num::cast(20f32)));
|
|
||||||
assert!((20f64 == num::cast(20f64)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
||||||
//
|
|
@ -1,757 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations and constants for `float`
|
|
||||||
|
|
||||||
// Even though this module exports everything defined in it,
|
|
||||||
// because it contains re-exports, we also have to explicitly
|
|
||||||
// export locally defined things. That's a bit annoying.
|
|
||||||
|
|
||||||
|
|
||||||
// export when m_float == c_double
|
|
||||||
|
|
||||||
|
|
||||||
// PORT this must match in width according to architecture
|
|
||||||
|
|
||||||
use f64;
|
|
||||||
use num::NumCast;
|
|
||||||
use num::strconv;
|
|
||||||
use num;
|
|
||||||
use option::Option;
|
|
||||||
use to_str;
|
|
||||||
use from_str;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
|
||||||
#[cfg(notest)] use ops;
|
|
||||||
#[cfg(test)] use option::{Some, None};
|
|
||||||
|
|
||||||
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
|
|
||||||
pub use f64::logarithm;
|
|
||||||
pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor};
|
|
||||||
pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub};
|
|
||||||
pub use f64::{mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp};
|
|
||||||
pub use f64::{lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix};
|
|
||||||
pub use f64::{modf, pow, round, sinh, tanh, tgamma, trunc};
|
|
||||||
pub use f64::signbit;
|
|
||||||
pub use f64::{j0, j1, jn, y0, y1, yn};
|
|
||||||
|
|
||||||
pub static NaN: float = 0.0/0.0;
|
|
||||||
|
|
||||||
pub static infinity: float = 1.0/0.0;
|
|
||||||
|
|
||||||
pub static neg_infinity: float = -1.0/0.0;
|
|
||||||
|
|
||||||
/* Module: consts */
|
|
||||||
pub mod consts {
|
|
||||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
|
||||||
// staticants from cmath.
|
|
||||||
/// Archimedes' staticant
|
|
||||||
pub static pi: float = 3.14159265358979323846264338327950288;
|
|
||||||
|
|
||||||
/// pi/2.0
|
|
||||||
pub static frac_pi_2: float = 1.57079632679489661923132169163975144;
|
|
||||||
|
|
||||||
/// pi/4.0
|
|
||||||
pub static frac_pi_4: float = 0.785398163397448309615660845819875721;
|
|
||||||
|
|
||||||
/// 1.0/pi
|
|
||||||
pub static frac_1_pi: float = 0.318309886183790671537767526745028724;
|
|
||||||
|
|
||||||
/// 2.0/pi
|
|
||||||
pub static frac_2_pi: float = 0.636619772367581343075535053490057448;
|
|
||||||
|
|
||||||
/// 2.0/sqrt(pi)
|
|
||||||
pub static frac_2_sqrtpi: float = 1.12837916709551257389615890312154517;
|
|
||||||
|
|
||||||
/// sqrt(2.0)
|
|
||||||
pub static sqrt2: float = 1.41421356237309504880168872420969808;
|
|
||||||
|
|
||||||
/// 1.0/sqrt(2.0)
|
|
||||||
pub static frac_1_sqrt2: float = 0.707106781186547524400844362104849039;
|
|
||||||
|
|
||||||
/// Euler's number
|
|
||||||
pub static e: float = 2.71828182845904523536028747135266250;
|
|
||||||
|
|
||||||
/// log2(e)
|
|
||||||
pub static log2_e: float = 1.44269504088896340735992468100189214;
|
|
||||||
|
|
||||||
/// log10(e)
|
|
||||||
pub static log10_e: float = 0.434294481903251827651128918916605082;
|
|
||||||
|
|
||||||
/// ln(2.0)
|
|
||||||
pub static ln_2: float = 0.693147180559945309417232121458176568;
|
|
||||||
|
|
||||||
/// ln(10.0)
|
|
||||||
pub static ln_10: float = 2.30258509299404568401799145468436421;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Section: String Conversions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str(num: float) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in hexadecimal format
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_hex(num: float) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*
|
|
||||||
* # Failure
|
|
||||||
*
|
|
||||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
|
||||||
* possible misinterpretation of the result at higher bases. If those values
|
|
||||||
* are expected, use `to_str_radix_special()` instead.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix(num: float, radix: uint) -> ~str {
|
|
||||||
let (r, special) = strconv::to_str_common(
|
|
||||||
&num, radix, true, strconv::SignNeg, strconv::DigAll);
|
|
||||||
if special { fail!(~"number has a special value, \
|
|
||||||
try to_str_radix_special() if those are expected") }
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string in a given radix, and a flag indicating
|
|
||||||
* whether it's a special value
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * radix - The base to use
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
|
||||||
strconv::to_str_common(&num, radix, true,
|
|
||||||
strconv::SignNeg, strconv::DigAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with exactly the number of
|
|
||||||
* provided significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_exact(num: float, digits: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(digits));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_str_exact_do_decimal() {
|
|
||||||
let s = to_str_exact(5.0, 4u);
|
|
||||||
assert!(s == ~"5.0000");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a float to a string with a maximum number of
|
|
||||||
* significant digits
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - The float value
|
|
||||||
* * digits - The number of significant digits
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_digits(num: float, digits: uint) -> ~str {
|
|
||||||
let (r, _) = strconv::to_str_common(
|
|
||||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(digits));
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
impl to_str::ToStr for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::ToStrRadix for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str_radix(&self, radix: uint) -> ~str {
|
|
||||||
to_str_radix(*self, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 10 to a float.
|
|
||||||
* Accepts a optional decimal exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * '3.14'
|
|
||||||
* * '+3.14', equivalent to '3.14'
|
|
||||||
* * '-3.14'
|
|
||||||
* * '2.5E10', or equivalently, '2.5e10'
|
|
||||||
* * '2.5E-10'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * '5.'
|
|
||||||
* * '.5', or, equivalently, '0.5'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str(num: &str) -> Option<float> {
|
|
||||||
strconv::from_str_common(num, 10u, true, true, true,
|
|
||||||
strconv::ExpDec, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in base 16 to a float.
|
|
||||||
* Accepts a optional binary exponent.
|
|
||||||
*
|
|
||||||
* This function accepts strings such as
|
|
||||||
*
|
|
||||||
* * 'a4.fe'
|
|
||||||
* * '+a4.fe', equivalent to 'a4.fe'
|
|
||||||
* * '-a4.fe'
|
|
||||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
|
||||||
* * '2b.aP-128'
|
|
||||||
* * '.' (understood as 0)
|
|
||||||
* * 'c.'
|
|
||||||
* * '.c', or, equivalently, '0.c'
|
|
||||||
* * '+inf', 'inf', '-inf', 'NaN'
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_hex(num: &str) -> Option<float> {
|
|
||||||
strconv::from_str_common(num, 16u, true, true, true,
|
|
||||||
strconv::ExpBin, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a string in an given base to a float.
|
|
||||||
*
|
|
||||||
* Due to possible conflicts, this function does **not** accept
|
|
||||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
|
||||||
* does it recognize exponents of any kind.
|
|
||||||
*
|
|
||||||
* Leading and trailing whitespace represent an error.
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * num - A string
|
|
||||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `none` if the string did not represent a valid number. Otherwise,
|
|
||||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
|
|
||||||
strconv::from_str_common(num, radix, true, true, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl from_str::FromStr for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str(val: &str) -> Option<float> { from_str(val) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::FromStrRadix for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str_radix(val: &str, radix: uint) -> Option<float> {
|
|
||||||
from_str_radix(val, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Section: Arithmetics
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the exponentiation of an integer by another integer as a float
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * x - The base
|
|
||||||
* * pow - The exponent
|
|
||||||
*
|
|
||||||
* # Return value
|
|
||||||
*
|
|
||||||
* `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
|
|
||||||
*/
|
|
||||||
pub fn pow_with_uint(base: uint, pow: uint) -> float {
|
|
||||||
if base == 0u {
|
|
||||||
if pow == 0u {
|
|
||||||
return NaN as float;
|
|
||||||
}
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
let mut my_pow = pow;
|
|
||||||
let mut total = 1f;
|
|
||||||
let mut multiplier = base as float;
|
|
||||||
while (my_pow > 0u) {
|
|
||||||
if my_pow % 2u == 1u {
|
|
||||||
total = total * multiplier;
|
|
||||||
}
|
|
||||||
my_pow /= 2u;
|
|
||||||
multiplier *= multiplier;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn abs(x: float) -> float {
|
|
||||||
unsafe { f64::abs(x as f64) as float }
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sqrt(x: float) -> float {
|
|
||||||
unsafe { f64::sqrt(x as f64) as float }
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn atan(x: float) -> float {
|
|
||||||
unsafe { f64::atan(x as f64) as float }
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sin(x: float) -> float {
|
|
||||||
unsafe { f64::sin(x as f64) as float }
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn cos(x: float) -> float {
|
|
||||||
unsafe { f64::cos(x as f64) as float }
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn tan(x: float) -> float {
|
|
||||||
unsafe { f64::tan(x as f64) as float }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl Eq for float {
|
|
||||||
fn eq(&self, other: &float) -> bool { (*self) == (*other) }
|
|
||||||
fn ne(&self, other: &float) -> bool { (*self) != (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl Ord for float {
|
|
||||||
fn lt(&self, other: &float) -> bool { (*self) < (*other) }
|
|
||||||
fn le(&self, other: &float) -> bool { (*self) <= (*other) }
|
|
||||||
fn ge(&self, other: &float) -> bool { (*self) >= (*other) }
|
|
||||||
fn gt(&self, other: &float) -> bool { (*self) > (*other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Zero for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn zero() -> float { 0.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::One for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn one() -> float { 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NumCast for float {
|
|
||||||
/**
|
|
||||||
* Cast `n` to a `float`
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
fn from<N:NumCast>(n: N) -> float { n.to_float() }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
|
||||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
|
||||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
|
||||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
|
||||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
|
||||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
|
||||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
|
||||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
|
||||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
|
||||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
|
||||||
#[inline(always)] fn to_float(&self) -> float { *self }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Round for float {
|
|
||||||
#[inline(always)]
|
|
||||||
fn round(&self, mode: num::RoundMode) -> float {
|
|
||||||
match mode {
|
|
||||||
num::RoundDown
|
|
||||||
=> f64::floor(*self as f64) as float,
|
|
||||||
num::RoundUp
|
|
||||||
=> f64::ceil(*self as f64) as float,
|
|
||||||
num::RoundToZero if is_negative(*self)
|
|
||||||
=> f64::ceil(*self as f64) as float,
|
|
||||||
num::RoundToZero
|
|
||||||
=> f64::floor(*self as f64) as float,
|
|
||||||
num::RoundFromZero if is_negative(*self)
|
|
||||||
=> f64::floor(*self as f64) as float,
|
|
||||||
num::RoundFromZero
|
|
||||||
=> f64::ceil(*self as f64) as float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn floor(&self) -> float { f64::floor(*self as f64) as float}
|
|
||||||
#[inline(always)]
|
|
||||||
fn ceil(&self) -> float { f64::ceil(*self as f64) as float}
|
|
||||||
#[inline(always)]
|
|
||||||
fn fract(&self) -> float {
|
|
||||||
if is_negative(*self) {
|
|
||||||
(*self) - (f64::ceil(*self as f64) as float)
|
|
||||||
} else {
|
|
||||||
(*self) - (f64::floor(*self as f64) as float)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Add<float,float> for float {
|
|
||||||
fn add(&self, other: &float) -> float { *self + *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Sub<float,float> for float {
|
|
||||||
fn sub(&self, other: &float) -> float { *self - *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Mul<float,float> for float {
|
|
||||||
fn mul(&self, other: &float) -> float { *self * *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Div<float,float> for float {
|
|
||||||
fn div(&self, other: &float) -> float { *self / *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Modulo<float,float> for float {
|
|
||||||
fn modulo(&self, other: &float) -> float { *self % *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Neg<float> for float {
|
|
||||||
fn neg(&self) -> float { -*self }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_str() {
|
|
||||||
assert!(from_str(~"3") == Some(3.));
|
|
||||||
assert!(from_str(~"3.14") == Some(3.14));
|
|
||||||
assert!(from_str(~"+3.14") == Some(3.14));
|
|
||||||
assert!(from_str(~"-3.14") == Some(-3.14));
|
|
||||||
assert!(from_str(~"2.5E10") == Some(25000000000.));
|
|
||||||
assert!(from_str(~"2.5e10") == Some(25000000000.));
|
|
||||||
assert!(from_str(~"25000000000.E-10") == Some(2.5));
|
|
||||||
assert!(from_str(~".") == Some(0.));
|
|
||||||
assert!(from_str(~".e1") == Some(0.));
|
|
||||||
assert!(from_str(~".e-1") == Some(0.));
|
|
||||||
assert!(from_str(~"5.") == Some(5.));
|
|
||||||
assert!(from_str(~".5") == Some(0.5));
|
|
||||||
assert!(from_str(~"0.5") == Some(0.5));
|
|
||||||
assert!(from_str(~"-.5") == Some(-0.5));
|
|
||||||
assert!(from_str(~"-5") == Some(-5.));
|
|
||||||
assert!(from_str(~"inf") == Some(infinity));
|
|
||||||
assert!(from_str(~"+inf") == Some(infinity));
|
|
||||||
assert!(from_str(~"-inf") == Some(neg_infinity));
|
|
||||||
// note: NaN != NaN, hence this slightly complex test
|
|
||||||
match from_str(~"NaN") {
|
|
||||||
Some(f) => assert!(is_NaN(f)),
|
|
||||||
None => fail!()
|
|
||||||
}
|
|
||||||
// note: -0 == 0, hence these slightly more complex tests
|
|
||||||
match from_str(~"-0") {
|
|
||||||
Some(v) if is_zero(v) => assert!(is_negative(v)),
|
|
||||||
_ => fail!()
|
|
||||||
}
|
|
||||||
match from_str(~"0") {
|
|
||||||
Some(v) if is_zero(v) => assert!(is_positive(v)),
|
|
||||||
_ => fail!()
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(from_str(~"").is_none());
|
|
||||||
assert!(from_str(~"x").is_none());
|
|
||||||
assert!(from_str(~" ").is_none());
|
|
||||||
assert!(from_str(~" ").is_none());
|
|
||||||
assert!(from_str(~"e").is_none());
|
|
||||||
assert!(from_str(~"E").is_none());
|
|
||||||
assert!(from_str(~"E1").is_none());
|
|
||||||
assert!(from_str(~"1e1e1").is_none());
|
|
||||||
assert!(from_str(~"1e1.1").is_none());
|
|
||||||
assert!(from_str(~"1e1-1").is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_str_hex() {
|
|
||||||
assert!(from_str_hex(~"a4") == Some(164.));
|
|
||||||
assert!(from_str_hex(~"a4.fe") == Some(164.9921875));
|
|
||||||
assert!(from_str_hex(~"-a4.fe") == Some(-164.9921875));
|
|
||||||
assert!(from_str_hex(~"+a4.fe") == Some(164.9921875));
|
|
||||||
assert!(from_str_hex(~"ff0P4") == Some(0xff00 as float));
|
|
||||||
assert!(from_str_hex(~"ff0p4") == Some(0xff00 as float));
|
|
||||||
assert!(from_str_hex(~"ff0p-4") == Some(0xff as float));
|
|
||||||
assert!(from_str_hex(~".") == Some(0.));
|
|
||||||
assert!(from_str_hex(~".p1") == Some(0.));
|
|
||||||
assert!(from_str_hex(~".p-1") == Some(0.));
|
|
||||||
assert!(from_str_hex(~"f.") == Some(15.));
|
|
||||||
assert!(from_str_hex(~".f") == Some(0.9375));
|
|
||||||
assert!(from_str_hex(~"0.f") == Some(0.9375));
|
|
||||||
assert!(from_str_hex(~"-.f") == Some(-0.9375));
|
|
||||||
assert!(from_str_hex(~"-f") == Some(-15.));
|
|
||||||
assert!(from_str_hex(~"inf") == Some(infinity));
|
|
||||||
assert!(from_str_hex(~"+inf") == Some(infinity));
|
|
||||||
assert!(from_str_hex(~"-inf") == Some(neg_infinity));
|
|
||||||
// note: NaN != NaN, hence this slightly complex test
|
|
||||||
match from_str_hex(~"NaN") {
|
|
||||||
Some(f) => assert!(is_NaN(f)),
|
|
||||||
None => fail!()
|
|
||||||
}
|
|
||||||
// note: -0 == 0, hence these slightly more complex tests
|
|
||||||
match from_str_hex(~"-0") {
|
|
||||||
Some(v) if is_zero(v) => assert!(is_negative(v)),
|
|
||||||
_ => fail!()
|
|
||||||
}
|
|
||||||
match from_str_hex(~"0") {
|
|
||||||
Some(v) if is_zero(v) => assert!(is_positive(v)),
|
|
||||||
_ => fail!()
|
|
||||||
}
|
|
||||||
assert!(from_str_hex(~"e") == Some(14.));
|
|
||||||
assert!(from_str_hex(~"E") == Some(14.));
|
|
||||||
assert!(from_str_hex(~"E1") == Some(225.));
|
|
||||||
assert!(from_str_hex(~"1e1e1") == Some(123361.));
|
|
||||||
assert!(from_str_hex(~"1e1.1") == Some(481.0625));
|
|
||||||
|
|
||||||
assert!(from_str_hex(~"").is_none());
|
|
||||||
assert!(from_str_hex(~"x").is_none());
|
|
||||||
assert!(from_str_hex(~" ").is_none());
|
|
||||||
assert!(from_str_hex(~" ").is_none());
|
|
||||||
assert!(from_str_hex(~"p").is_none());
|
|
||||||
assert!(from_str_hex(~"P").is_none());
|
|
||||||
assert!(from_str_hex(~"P1").is_none());
|
|
||||||
assert!(from_str_hex(~"1p1p1").is_none());
|
|
||||||
assert!(from_str_hex(~"1p1.1").is_none());
|
|
||||||
assert!(from_str_hex(~"1p1-1").is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_str_hex() {
|
|
||||||
assert!(to_str_hex(164.) == ~"a4");
|
|
||||||
assert!(to_str_hex(164.9921875) == ~"a4.fe");
|
|
||||||
assert!(to_str_hex(-164.9921875) == ~"-a4.fe");
|
|
||||||
assert!(to_str_hex(0xff00 as float) == ~"ff00");
|
|
||||||
assert!(to_str_hex(-(0xff00 as float)) == ~"-ff00");
|
|
||||||
assert!(to_str_hex(0.) == ~"0");
|
|
||||||
assert!(to_str_hex(15.) == ~"f");
|
|
||||||
assert!(to_str_hex(-15.) == ~"-f");
|
|
||||||
assert!(to_str_hex(0.9375) == ~"0.f");
|
|
||||||
assert!(to_str_hex(-0.9375) == ~"-0.f");
|
|
||||||
assert!(to_str_hex(infinity) == ~"inf");
|
|
||||||
assert!(to_str_hex(neg_infinity) == ~"-inf");
|
|
||||||
assert!(to_str_hex(NaN) == ~"NaN");
|
|
||||||
assert!(to_str_hex(0.) == ~"0");
|
|
||||||
assert!(to_str_hex(-0.) == ~"-0");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_str_radix() {
|
|
||||||
assert!(to_str_radix(36., 36u) == ~"10");
|
|
||||||
assert!(to_str_radix(8.125, 2u) == ~"1000.001");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_from_str_radix() {
|
|
||||||
assert!(from_str_radix(~"10", 36u) == Some(36.));
|
|
||||||
assert!(from_str_radix(~"1000.001", 2u) == Some(8.125));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_positive() {
|
|
||||||
assert!((is_positive(infinity)));
|
|
||||||
assert!((is_positive(1.)));
|
|
||||||
assert!((is_positive(0.)));
|
|
||||||
assert!((!is_positive(-1.)));
|
|
||||||
assert!((!is_positive(neg_infinity)));
|
|
||||||
assert!((!is_positive(1./neg_infinity)));
|
|
||||||
assert!((!is_positive(NaN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_negative() {
|
|
||||||
assert!((!is_negative(infinity)));
|
|
||||||
assert!((!is_negative(1.)));
|
|
||||||
assert!((!is_negative(0.)));
|
|
||||||
assert!((is_negative(-1.)));
|
|
||||||
assert!((is_negative(neg_infinity)));
|
|
||||||
assert!((is_negative(1./neg_infinity)));
|
|
||||||
assert!((!is_negative(NaN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_nonpositive() {
|
|
||||||
assert!((!is_nonpositive(infinity)));
|
|
||||||
assert!((!is_nonpositive(1.)));
|
|
||||||
assert!((!is_nonpositive(0.)));
|
|
||||||
assert!((is_nonpositive(-1.)));
|
|
||||||
assert!((is_nonpositive(neg_infinity)));
|
|
||||||
assert!((is_nonpositive(1./neg_infinity)));
|
|
||||||
assert!((!is_nonpositive(NaN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_nonnegative() {
|
|
||||||
assert!((is_nonnegative(infinity)));
|
|
||||||
assert!((is_nonnegative(1.)));
|
|
||||||
assert!((is_nonnegative(0.)));
|
|
||||||
assert!((!is_nonnegative(-1.)));
|
|
||||||
assert!((!is_nonnegative(neg_infinity)));
|
|
||||||
assert!((!is_nonnegative(1./neg_infinity)));
|
|
||||||
assert!((!is_nonnegative(NaN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_to_str_inf() {
|
|
||||||
assert!(to_str_digits(infinity, 10u) == ~"inf");
|
|
||||||
assert!(to_str_digits(-infinity, 10u) == ~"-inf");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_round() {
|
|
||||||
assert!(round(5.8) == 6.0);
|
|
||||||
assert!(round(5.2) == 5.0);
|
|
||||||
assert!(round(3.0) == 3.0);
|
|
||||||
assert!(round(2.5) == 3.0);
|
|
||||||
assert!(round(-3.5) == -4.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_num() {
|
|
||||||
let ten: float = num::cast(10);
|
|
||||||
let two: float = num::cast(2);
|
|
||||||
|
|
||||||
assert!((ten.add(&two) == num::cast(12)));
|
|
||||||
assert!((ten.sub(&two) == num::cast(8)));
|
|
||||||
assert!((ten.mul(&two) == num::cast(20)));
|
|
||||||
assert!((ten.div(&two) == num::cast(5)));
|
|
||||||
assert!((ten.modulo(&two) == num::cast(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_numcast() {
|
|
||||||
assert!((20u == 20f.to_uint()));
|
|
||||||
assert!((20u8 == 20f.to_u8()));
|
|
||||||
assert!((20u16 == 20f.to_u16()));
|
|
||||||
assert!((20u32 == 20f.to_u32()));
|
|
||||||
assert!((20u64 == 20f.to_u64()));
|
|
||||||
assert!((20i == 20f.to_int()));
|
|
||||||
assert!((20i8 == 20f.to_i8()));
|
|
||||||
assert!((20i16 == 20f.to_i16()));
|
|
||||||
assert!((20i32 == 20f.to_i32()));
|
|
||||||
assert!((20i64 == 20f.to_i64()));
|
|
||||||
assert!((20f == 20f.to_float()));
|
|
||||||
assert!((20f32 == 20f.to_f32()));
|
|
||||||
assert!((20f64 == 20f.to_f64()));
|
|
||||||
|
|
||||||
assert!((20f == NumCast::from(20u)));
|
|
||||||
assert!((20f == NumCast::from(20u8)));
|
|
||||||
assert!((20f == NumCast::from(20u16)));
|
|
||||||
assert!((20f == NumCast::from(20u32)));
|
|
||||||
assert!((20f == NumCast::from(20u64)));
|
|
||||||
assert!((20f == NumCast::from(20i)));
|
|
||||||
assert!((20f == NumCast::from(20i8)));
|
|
||||||
assert!((20f == NumCast::from(20i16)));
|
|
||||||
assert!((20f == NumCast::from(20i32)));
|
|
||||||
assert!((20f == NumCast::from(20i64)));
|
|
||||||
assert!((20f == NumCast::from(20f)));
|
|
||||||
assert!((20f == NumCast::from(20f32)));
|
|
||||||
assert!((20f == NumCast::from(20f64)));
|
|
||||||
|
|
||||||
assert!((20f == num::cast(20u)));
|
|
||||||
assert!((20f == num::cast(20u8)));
|
|
||||||
assert!((20f == num::cast(20u16)));
|
|
||||||
assert!((20f == num::cast(20u32)));
|
|
||||||
assert!((20f == num::cast(20u64)));
|
|
||||||
assert!((20f == num::cast(20i)));
|
|
||||||
assert!((20f == num::cast(20i8)));
|
|
||||||
assert!((20f == num::cast(20i16)));
|
|
||||||
assert!((20f == num::cast(20i32)));
|
|
||||||
assert!((20f == num::cast(20i64)));
|
|
||||||
assert!((20f == num::cast(20f)));
|
|
||||||
assert!((20f == num::cast(20f32)));
|
|
||||||
assert!((20f == num::cast(20f64)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Local Variables:
|
|
||||||
// mode: rust
|
|
||||||
// fill-column: 78;
|
|
||||||
// indent-tabs-mode: nil
|
|
||||||
// c-basic-offset: 4
|
|
||||||
// buffer-file-coding-system: utf-8-unix
|
|
||||||
// End:
|
|
||||||
//
|
|
@ -1,449 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use T = self::inst::T;
|
|
||||||
|
|
||||||
use to_str::ToStr;
|
|
||||||
use from_str::FromStr;
|
|
||||||
use num::{ToStrRadix, FromStrRadix};
|
|
||||||
use num::strconv;
|
|
||||||
use num;
|
|
||||||
use prelude::*;
|
|
||||||
|
|
||||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
|
||||||
|
|
||||||
pub use cmp::{min, max};
|
|
||||||
|
|
||||||
pub static bits : uint = inst::bits;
|
|
||||||
pub static bytes : uint = (inst::bits / 8);
|
|
||||||
|
|
||||||
pub static min_value: T = (-1 as T) << (bits - 1);
|
|
||||||
pub static max_value: T = min_value - 1 as T;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn add(x: T, y: T) -> T { x + y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn sub(x: T, y: T) -> T { x - y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn mul(x: T, y: T) -> T { x * y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn div(x: T, y: T) -> T { x / y }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the remainder of y / x.
|
|
||||||
*
|
|
||||||
* # Examples
|
|
||||||
* ~~~
|
|
||||||
* assert!(int::rem(5 / 2) == 1);
|
|
||||||
* ~~~
|
|
||||||
*
|
|
||||||
* When faced with negative numbers, the result copies the sign of the
|
|
||||||
* dividend.
|
|
||||||
*
|
|
||||||
* ~~~
|
|
||||||
* assert!(int::rem(2 / -3) == 2);
|
|
||||||
* ~~~
|
|
||||||
*
|
|
||||||
* ~~~
|
|
||||||
* assert!(int::rem(-2 / 3) == -2);
|
|
||||||
* ~~~
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn rem(x: T, y: T) -> T { x % y }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lt(x: T, y: T) -> bool { x < y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn le(x: T, y: T) -> bool { x <= y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn eq(x: T, y: T) -> bool { x == y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ne(x: T, y: T) -> bool { x != y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn ge(x: T, y: T) -> bool { x >= y }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn gt(x: T, y: T) -> bool { x > y }
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_positive(x: T) -> bool { x > 0 as T }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_negative(x: T) -> bool { x < 0 as T }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonpositive(x: T) -> bool { x <= 0 as T }
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_nonnegative(x: T) -> bool { x >= 0 as T }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over the range [`lo`..`hi`)
|
|
||||||
*
|
|
||||||
* # Arguments
|
|
||||||
*
|
|
||||||
* * `lo` - lower bound, inclusive
|
|
||||||
* * `hi` - higher bound, exclusive
|
|
||||||
*
|
|
||||||
* # Examples
|
|
||||||
* ~~~
|
|
||||||
* let mut sum = 0;
|
|
||||||
* for int::range(1, 5) |i| {
|
|
||||||
* sum += i;
|
|
||||||
* }
|
|
||||||
* assert!(sum == 10);
|
|
||||||
* ~~~
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
/// Iterate over the range [`start`,`start`+`step`..`stop`)
|
|
||||||
pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) {
|
|
||||||
let mut i = start;
|
|
||||||
if step == 0 {
|
|
||||||
fail!(~"range_step called with step == 0");
|
|
||||||
} else if step > 0 { // ascending
|
|
||||||
while i < stop {
|
|
||||||
if !it(i) { break }
|
|
||||||
i += step;
|
|
||||||
}
|
|
||||||
} else { // descending
|
|
||||||
while i > stop {
|
|
||||||
if !it(i) { break }
|
|
||||||
i += step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
/// Iterate over the range [`lo`..`hi`)
|
|
||||||
pub fn range(lo: T, hi: T, it: &fn(T) -> bool) {
|
|
||||||
range_step(lo, hi, 1 as T, it);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
/// Iterate over the range [`hi`..`lo`)
|
|
||||||
pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) {
|
|
||||||
range_step(hi, lo, -1 as T, it);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the bitwise complement
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn compl(i: T) -> T {
|
|
||||||
-1 as T ^ i
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the absolute value
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn abs(i: T) -> T {
|
|
||||||
if is_negative(i) { -i } else { i }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl Ord for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn lt(&self, other: &T) -> bool { return (*self) < (*other); }
|
|
||||||
#[inline(always)]
|
|
||||||
fn le(&self, other: &T) -> bool { return (*self) <= (*other); }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ge(&self, other: &T) -> bool { return (*self) >= (*other); }
|
|
||||||
#[inline(always)]
|
|
||||||
fn gt(&self, other: &T) -> bool { return (*self) > (*other); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl Eq for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &T) -> bool { return (*self) == (*other); }
|
|
||||||
#[inline(always)]
|
|
||||||
fn ne(&self, other: &T) -> bool { return (*self) != (*other); }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Zero for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn zero() -> T { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::One for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn one() -> T { 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Add<T,T> for T {
|
|
||||||
fn add(&self, other: &T) -> T { *self + *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Sub<T,T> for T {
|
|
||||||
fn sub(&self, other: &T) -> T { *self - *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Mul<T,T> for T {
|
|
||||||
fn mul(&self, other: &T) -> T { *self * *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Div<T,T> for T {
|
|
||||||
fn div(&self, other: &T) -> T { *self / *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Modulo<T,T> for T {
|
|
||||||
fn modulo(&self, other: &T) -> T { *self % *other }
|
|
||||||
}
|
|
||||||
#[cfg(notest)]
|
|
||||||
impl ops::Neg<T> for T {
|
|
||||||
fn neg(&self) -> T { -*self }
|
|
||||||
}
|
|
||||||
|
|
||||||
// String conversion functions and impl str -> num
|
|
||||||
|
|
||||||
/// Parse a string as a number in base 10.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str(s: &str) -> Option<T> {
|
|
||||||
strconv::from_str_common(s, 10u, true, false, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a string as a number in the given base.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
|
||||||
strconv::from_str_common(s, radix, true, false, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a byte slice as a number in the given base.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
|
|
||||||
strconv::from_str_bytes_common(buf, radix, true, false, false,
|
|
||||||
strconv::ExpNone, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str(s: &str) -> Option<T> {
|
|
||||||
from_str(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStrRadix for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
|
||||||
from_str_radix(s, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String conversion functions and impl num -> str
|
|
||||||
|
|
||||||
/// Convert to a string as a byte slice in a given base.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_bytes<U>(n: T, radix: uint, f: &fn(v: &[u8]) -> U) -> U {
|
|
||||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
|
||||||
strconv::SignNeg, strconv::DigAll);
|
|
||||||
f(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert to a string in base 10.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str(num: T) -> ~str {
|
|
||||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
|
||||||
strconv::SignNeg, strconv::DigAll);
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert to a string in a given base.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_str_radix(num: T, radix: uint) -> ~str {
|
|
||||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
|
||||||
strconv::SignNeg, strconv::DigAll);
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToStr for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str(&self) -> ~str {
|
|
||||||
to_str(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToStrRadix for T {
|
|
||||||
#[inline(always)]
|
|
||||||
fn to_str_radix(&self, radix: uint) -> ~str {
|
|
||||||
to_str_radix(*self, radix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_str() {
|
|
||||||
assert!(from_str(~"0") == Some(0 as T));
|
|
||||||
assert!(from_str(~"3") == Some(3 as T));
|
|
||||||
assert!(from_str(~"10") == Some(10 as T));
|
|
||||||
assert!(i32::from_str(~"123456789") == Some(123456789 as i32));
|
|
||||||
assert!(from_str(~"00100") == Some(100 as T));
|
|
||||||
|
|
||||||
assert!(from_str(~"-1") == Some(-1 as T));
|
|
||||||
assert!(from_str(~"-3") == Some(-3 as T));
|
|
||||||
assert!(from_str(~"-10") == Some(-10 as T));
|
|
||||||
assert!(i32::from_str(~"-123456789") == Some(-123456789 as i32));
|
|
||||||
assert!(from_str(~"-00100") == Some(-100 as T));
|
|
||||||
|
|
||||||
assert!(from_str(~" ").is_none());
|
|
||||||
assert!(from_str(~"x").is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_bytes() {
|
|
||||||
use str::to_bytes;
|
|
||||||
assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"123"), 16u) == Some(291 as i32));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"ffff"), 16u) ==
|
|
||||||
Some(65535 as i32));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"FFFF"), 16u) ==
|
|
||||||
Some(65535 as i32));
|
|
||||||
assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T));
|
|
||||||
|
|
||||||
assert!(parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"-123"), 16u) ==
|
|
||||||
Some(-291 as i32));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"-ffff"), 16u) ==
|
|
||||||
Some(-65535 as i32));
|
|
||||||
assert!(i32::parse_bytes(to_bytes(~"-FFFF"), 16u) ==
|
|
||||||
Some(-65535 as i32));
|
|
||||||
assert!(parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T));
|
|
||||||
assert!(parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T));
|
|
||||||
|
|
||||||
assert!(parse_bytes(to_bytes(~"Z"), 35u).is_none());
|
|
||||||
assert!(parse_bytes(to_bytes(~"-9"), 2u).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_str() {
|
|
||||||
assert!((to_str_radix(0 as T, 10u) == ~"0"));
|
|
||||||
assert!((to_str_radix(1 as T, 10u) == ~"1"));
|
|
||||||
assert!((to_str_radix(-1 as T, 10u) == ~"-1"));
|
|
||||||
assert!((to_str_radix(127 as T, 16u) == ~"7f"));
|
|
||||||
assert!((to_str_radix(100 as T, 10u) == ~"100"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_int_to_str_overflow() {
|
|
||||||
let mut i8_val: i8 = 127_i8;
|
|
||||||
assert!((i8::to_str(i8_val) == ~"127"));
|
|
||||||
|
|
||||||
i8_val += 1 as i8;
|
|
||||||
assert!((i8::to_str(i8_val) == ~"-128"));
|
|
||||||
|
|
||||||
let mut i16_val: i16 = 32_767_i16;
|
|
||||||
assert!((i16::to_str(i16_val) == ~"32767"));
|
|
||||||
|
|
||||||
i16_val += 1 as i16;
|
|
||||||
assert!((i16::to_str(i16_val) == ~"-32768"));
|
|
||||||
|
|
||||||
let mut i32_val: i32 = 2_147_483_647_i32;
|
|
||||||
assert!((i32::to_str(i32_val) == ~"2147483647"));
|
|
||||||
|
|
||||||
i32_val += 1 as i32;
|
|
||||||
assert!((i32::to_str(i32_val) == ~"-2147483648"));
|
|
||||||
|
|
||||||
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
|
|
||||||
assert!((i64::to_str(i64_val) == ~"9223372036854775807"));
|
|
||||||
|
|
||||||
i64_val += 1 as i64;
|
|
||||||
assert!((i64::to_str(i64_val) == ~"-9223372036854775808"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_int_from_str_overflow() {
|
|
||||||
let mut i8_val: i8 = 127_i8;
|
|
||||||
assert!((i8::from_str(~"127") == Some(i8_val)));
|
|
||||||
assert!((i8::from_str(~"128").is_none()));
|
|
||||||
|
|
||||||
i8_val += 1 as i8;
|
|
||||||
assert!((i8::from_str(~"-128") == Some(i8_val)));
|
|
||||||
assert!((i8::from_str(~"-129").is_none()));
|
|
||||||
|
|
||||||
let mut i16_val: i16 = 32_767_i16;
|
|
||||||
assert!((i16::from_str(~"32767") == Some(i16_val)));
|
|
||||||
assert!((i16::from_str(~"32768").is_none()));
|
|
||||||
|
|
||||||
i16_val += 1 as i16;
|
|
||||||
assert!((i16::from_str(~"-32768") == Some(i16_val)));
|
|
||||||
assert!((i16::from_str(~"-32769").is_none()));
|
|
||||||
|
|
||||||
let mut i32_val: i32 = 2_147_483_647_i32;
|
|
||||||
assert!((i32::from_str(~"2147483647") == Some(i32_val)));
|
|
||||||
assert!((i32::from_str(~"2147483648").is_none()));
|
|
||||||
|
|
||||||
i32_val += 1 as i32;
|
|
||||||
assert!((i32::from_str(~"-2147483648") == Some(i32_val)));
|
|
||||||
assert!((i32::from_str(~"-2147483649").is_none()));
|
|
||||||
|
|
||||||
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
|
|
||||||
assert!((i64::from_str(~"9223372036854775807") == Some(i64_val)));
|
|
||||||
assert!((i64::from_str(~"9223372036854775808").is_none()));
|
|
||||||
|
|
||||||
i64_val += 1 as i64;
|
|
||||||
assert!((i64::from_str(~"-9223372036854775808") == Some(i64_val)));
|
|
||||||
assert!((i64::from_str(~"-9223372036854775809").is_none()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_num() {
|
|
||||||
let ten: T = num::cast(10);
|
|
||||||
let two: T = num::cast(2);
|
|
||||||
|
|
||||||
assert!((ten.add(&two) == num::cast(12)));
|
|
||||||
assert!((ten.sub(&two) == num::cast(8)));
|
|
||||||
assert!((ten.mul(&two) == num::cast(20)));
|
|
||||||
assert!((ten.div(&two) == num::cast(5)));
|
|
||||||
assert!((ten.modulo(&two) == num::cast(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_ranges() {
|
|
||||||
let mut l = ~[];
|
|
||||||
|
|
||||||
for range(0,3) |i| {
|
|
||||||
l.push(i);
|
|
||||||
}
|
|
||||||
for range_rev(13,10) |i| {
|
|
||||||
l.push(i);
|
|
||||||
}
|
|
||||||
for range_step(20,26,2) |i| {
|
|
||||||
l.push(i);
|
|
||||||
}
|
|
||||||
for range_step(36,30,-2) |i| {
|
|
||||||
l.push(i);
|
|
||||||
}
|
|
||||||
assert!(l == ~[0,1,2,
|
|
||||||
13,12,11,
|
|
||||||
20,22,24,
|
|
||||||
36,34,32]);
|
|
||||||
|
|
||||||
// None of the `fail`s should execute.
|
|
||||||
for range(10,0) |_i| {
|
|
||||||
fail!(~"unreachable");
|
|
||||||
}
|
|
||||||
for range_rev(0,10) |_i| {
|
|
||||||
fail!(~"unreachable");
|
|
||||||
}
|
|
||||||
for range_step(10,0,1) |_i| {
|
|
||||||
fail!(~"unreachable");
|
|
||||||
}
|
|
||||||
for range_step(0,10,-1) |_i| {
|
|
||||||
fail!(~"unreachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_fail]
|
|
||||||
#[ignore(cfg(windows))]
|
|
||||||
fn test_range_step_zero_step() {
|
|
||||||
for range_step(0,10,0) |_i| {}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations and constants for `i16`
|
|
||||||
|
|
||||||
use num::NumCast;
|
|
||||||
|
|
||||||
mod inst {
|
|
||||||
pub type T = i16;
|
|
||||||
pub static bits: uint = ::u16::bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NumCast for i16 {
|
|
||||||
/**
|
|
||||||
* Cast `n` to a `i16`
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
fn from<N:NumCast>(n: N) -> i16 { n.to_i16() }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
|
||||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
|
||||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
|
||||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
|
||||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
|
||||||
#[inline(always)] fn to_i16(&self) -> i16 { *self }
|
|
||||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
|
||||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
|
||||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
|
||||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
|
||||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_numcast() {
|
|
||||||
assert!((20u == 20i16.to_uint()));
|
|
||||||
assert!((20u8 == 20i16.to_u8()));
|
|
||||||
assert!((20u16 == 20i16.to_u16()));
|
|
||||||
assert!((20u32 == 20i16.to_u32()));
|
|
||||||
assert!((20u64 == 20i16.to_u64()));
|
|
||||||
assert!((20i == 20i16.to_int()));
|
|
||||||
assert!((20i8 == 20i16.to_i8()));
|
|
||||||
assert!((20i16 == 20i16.to_i16()));
|
|
||||||
assert!((20i32 == 20i16.to_i32()));
|
|
||||||
assert!((20i64 == 20i16.to_i64()));
|
|
||||||
assert!((20f == 20i16.to_float()));
|
|
||||||
assert!((20f32 == 20i16.to_f32()));
|
|
||||||
assert!((20f64 == 20i16.to_f64()));
|
|
||||||
|
|
||||||
assert!((20i16 == NumCast::from(20u)));
|
|
||||||
assert!((20i16 == NumCast::from(20u8)));
|
|
||||||
assert!((20i16 == NumCast::from(20u16)));
|
|
||||||
assert!((20i16 == NumCast::from(20u32)));
|
|
||||||
assert!((20i16 == NumCast::from(20u64)));
|
|
||||||
assert!((20i16 == NumCast::from(20i)));
|
|
||||||
assert!((20i16 == NumCast::from(20i8)));
|
|
||||||
assert!((20i16 == NumCast::from(20i16)));
|
|
||||||
assert!((20i16 == NumCast::from(20i32)));
|
|
||||||
assert!((20i16 == NumCast::from(20i64)));
|
|
||||||
assert!((20i16 == NumCast::from(20f)));
|
|
||||||
assert!((20i16 == NumCast::from(20f32)));
|
|
||||||
assert!((20i16 == NumCast::from(20f64)));
|
|
||||||
|
|
||||||
assert!((20i16 == num::cast(20u)));
|
|
||||||
assert!((20i16 == num::cast(20u8)));
|
|
||||||
assert!((20i16 == num::cast(20u16)));
|
|
||||||
assert!((20i16 == num::cast(20u32)));
|
|
||||||
assert!((20i16 == num::cast(20u64)));
|
|
||||||
assert!((20i16 == num::cast(20i)));
|
|
||||||
assert!((20i16 == num::cast(20i8)));
|
|
||||||
assert!((20i16 == num::cast(20i16)));
|
|
||||||
assert!((20i16 == num::cast(20i32)));
|
|
||||||
assert!((20i16 == num::cast(20i64)));
|
|
||||||
assert!((20i16 == num::cast(20f)));
|
|
||||||
assert!((20i16 == num::cast(20f32)));
|
|
||||||
assert!((20i16 == num::cast(20f64)));
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! Operations and constants for `i32`
|
|
||||||
|
|
||||||
use num::NumCast;
|
|
||||||
|
|
||||||
mod inst {
|
|
||||||
pub type T = i32;
|
|
||||||
pub static bits: uint = ::u32::bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NumCast for i32 {
|
|
||||||
/**
|
|
||||||
* Cast `n` to a `i32`
|
|
||||||
*/
|
|
||||||
#[inline(always)]
|
|
||||||
fn from<N:NumCast>(n: N) -> i32 { n.to_i32() }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
|
||||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
|
||||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
|
||||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
|
||||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
|
||||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
|
||||||
#[inline(always)] fn to_i32(&self) -> i32 { *self }
|
|
||||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
|
||||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
|
||||||
|
|
||||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
|
||||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
|
||||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_numcast() {
|
|
||||||
assert!((20u == 20i32.to_uint()));
|
|
||||||
assert!((20u8 == 20i32.to_u8()));
|
|
||||||
assert!((20u16 == 20i32.to_u16()));
|
|
||||||
assert!((20u32 == 20i32.to_u32()));
|
|
||||||
assert!((20u64 == 20i32.to_u64()));
|
|
||||||
assert!((20i == 20i32.to_int()));
|
|
||||||
assert!((20i8 == 20i32.to_i8()));
|
|
||||||
assert!((20i16 == 20i32.to_i16()));
|
|
||||||
assert!((20i32 == 20i32.to_i32()));
|
|
||||||
assert!((20i64 == 20i32.to_i64()));
|
|
||||||
assert!((20f == 20i32.to_float()));
|
|
||||||
assert!((20f32 == 20i32.to_f32()));
|
|
||||||
assert!((20f64 == 20i32.to_f64()));
|
|
||||||
|
|
||||||
assert!((20i32 == NumCast::from(20u)));
|
|
||||||
assert!((20i32 == NumCast::from(20u8)));
|
|
||||||
assert!((20i32 == NumCast::from(20u16)));
|
|
||||||
assert!((20i32 == NumCast::from(20u32)));
|
|
||||||
assert!((20i32 == NumCast::from(20u64)));
|
|
||||||
assert!((20i32 == NumCast::from(20i)));
|
|
||||||
assert!((20i32 == NumCast::from(20i8)));
|
|
||||||
assert!((20i32 == NumCast::from(20i16)));
|
|
||||||
assert!((20i32 == NumCast::from(20i32)));
|
|
||||||
assert!((20i32 == NumCast::from(20i64)));
|
|
||||||
assert!((20i32 == NumCast::from(20f)));
|
|
||||||
assert!((20i32 == NumCast::from(20f32)));
|
|
||||||
assert!((20i32 == NumCast::from(20f64)));
|
|
||||||
|
|
||||||
assert!((20i32 == num::cast(20u)));
|
|
||||||
assert!((20i32 == num::cast(20u8)));
|
|
||||||
assert!((20i32 == num::cast(20u16)));
|
|
||||||
assert!((20i32 == num::cast(20u32)));
|
|
||||||
assert!((20i32 == num::cast(20u64)));
|
|
||||||
assert!((20i32 == num::cast(20i)));
|
|
||||||
assert!((20i32 == num::cast(20i8)));
|
|
||||||
assert!((20i32 == num::cast(20i16)));
|
|
||||||
assert!((20i32 == num::cast(20i32)));
|
|
||||||
assert!((20i32 == num::cast(20i64)));
|
|
||||||
assert!((20i32 == num::cast(20f)));
|
|
||||||
assert!((20i32 == num::cast(20f32)));
|
|
||||||
assert!((20i32 == num::cast(20f64)));
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user