Imported Upstream version 0.7

This commit is contained in:
Luca Bruno 2013-08-26 15:26:48 +02:00
parent 223e47cc31
commit 970d7e83e1
12546 changed files with 425979 additions and 1533312 deletions

228
AUTHORS.txt Normal file
View 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>

View File

@ -367,4 +367,3 @@ their own copyright notices and license terms:
has chosen for the collective work, enumerated at the top
of this file. The only difference is the retention of
copyright itself, held by the contributor.

View File

@ -101,7 +101,7 @@ endif
ifdef CFG_ENABLE_DEBUG
$(info cfg: enabling more debugging (CFG_ENABLE_DEBUG))
CFG_RUSTC_FLAGS +=
CFG_RUSTC_FLAGS += --cfg debug
CFG_GCCISH_CFLAGS += -DRUST_DEBUG
else
CFG_GCCISH_CFLAGS += -DRUST_NDEBUG
@ -110,6 +110,9 @@ endif
ifdef SAVE_TEMPS
CFG_RUSTC_FLAGS += --save-temps
endif
ifdef ASM_COMMENTS
CFG_RUSTC_FLAGS += -Z asm-comments
endif
ifdef TIME_PASSES
CFG_RUSTC_FLAGS += -Z time-passes
endif
@ -119,6 +122,10 @@ endif
ifdef TRACE
CFG_RUSTC_FLAGS += -Z trace
endif
ifndef DEBUG_BORROWS
RUSTFLAGS_STAGE1 += -Z no-debug-borrows
RUSTFLAGS_STAGE2 += -Z no-debug-borrows
endif
# platform-specific auto-configuration
include $(CFG_SRC_DIR)mk/platform.mk
@ -132,15 +139,17 @@ endif
# version-string calculation
CFG_GIT_DIR := $(CFG_SRC_DIR).git
CFG_RELEASE = 0.6
CFG_RELEASE = 0.7
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_DIR)),)
CFG_VERSION += $(shell git --git-dir=$(CFG_GIT_DIR) log -1 \
--pretty=format:'(%h %ci)')
CFG_VER_HASH = $(shell git --git-dir=$(CFG_GIT_DIR) log -1 \
--pretty=format:'%H')
CFG_VER_HASH = $(shell git --git-dir=$(CFG_GIT_DIR) rev-parse HEAD)
endif
endif
@ -198,30 +207,27 @@ define DEF_LIBS
CFG_RUNTIME_$(1) :=$(call CFG_LIB_NAME_$(1),rustrt)
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_EXTRALIB_$(1) :=$(call CFG_LIB_NAME_$(1),extra)
CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
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_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
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)
CORELIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),core)
LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
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)
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
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)
CORELIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),core)
LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
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)
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
@ -232,33 +238,33 @@ endef
$(foreach target,$(CFG_TARGET_TRIPLES),\
$(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
######################################################################
STDLIB_CRATE := $(S)src/libstd/std.rc
STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \
std.rc *.rs */*.rs))
STDLIB_CRATE := $(S)src/libstd/std.rs
STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \
*.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
######################################################################
COMPILER_CRATE := $(S)src/librustc/rustc.rc
COMPILER_CRATE := $(S)src/librustc/rustc.rs
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/, \
syntax.rc *.rs */*.rs */*/*.rs))
*.rs */*.rs */*/*.rs))
DRIVER_CRATE := $(S)src/driver/driver.rs
@ -268,7 +274,7 @@ DRIVER_CRATE := $(S)src/driver/driver.rs
# FIXME: x86-ism
LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit \
interpreter
interpreter instrumentation
define DEF_LLVM_VARS
# 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_BUILD_DIR
export CFG_VERSION
export CFG_VERSION_WIN
export CFG_BUILD_TRIPLE
export CFG_LLVM_ROOT
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
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
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) = \
$$(HLIB$(1)_H_$(3))/libstd.rlib
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(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) = \
$$(HLIB$(1)_H_$(3))/librustc.rlib
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/librustc.rlib
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) = \
$$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
$$(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) = \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
@ -375,8 +382,8 @@ HSREQ$(1)_H_$(3) = \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_RUNTIME_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
$$(HCORELIB_DEFAULT$(1)_H_$(3)) \
$$(HSTDLIB_DEFAULT$(1)_H_$(3)) \
$$(HEXTRALIB_DEFAULT$(1)_H_$(3)) \
$$(HLIBSYNTAX_DEFAULT$(1)_H_$(3)) \
$$(HLIBRUSTC_DEFAULT$(1)_H_$(3)) \
$$(MKFILE_DEPS)
@ -390,27 +397,24 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
# Prerequisites for a working stageN compiler and libraries, for a specific target
SREQ$(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
CSREQ$(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))/rustdoc$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rusti$$(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_LIBRUSTDOC_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(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_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_LIBRUSTDOC_$(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), \
all-target-$(target)-host-$(host)))
all: $(ALL_TARGET_RULES) $(GENERATED) docs
all: rustllvm/llvm-auto-clean-stamp \
$(ALL_TARGET_RULES) $(GENERATED) docs
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

View File

@ -42,9 +42,9 @@ packages:
Assuming you're on a relatively modern *nix system and have met the
prerequisites, something along these lines should work.
$ curl -O http://static.rust-lang.org/dist/rust-0.6.tar.gz
$ tar -xzf rust-0.6.tar.gz
$ cd rust-0.6
$ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
$ tar -xzf rust-0.7.tar.gz
$ cd rust-0.7
$ ./configure
$ 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.
[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
[win-exe]: http://static.rust-lang.org/dist/rust-0.6-install.exe
[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
## License

98
configure vendored
View File

@ -138,7 +138,7 @@ validate_opt () {
done
if [ "$arg" = "--help" ]
then
echo ""
echo
echo "No more help available for Configure options,"
echo "check the Wiki or join our IRC channel"
break
@ -237,7 +237,7 @@ need_cmd uname
need_cmd date
need_cmd tr
need_cmd sed
need_cmd file
msg "inspecting environment"
@ -349,11 +349,11 @@ if [ "$1" = "--help" ]
then
HELP=1
shift
echo ""
echo
echo "Usage: $CFG_SELF [options]"
echo ""
echo
echo "Options:"
echo ""
echo
else
msg "recreating 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 mingw-cross 0 "cross-compile for win32 using mingw"
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 pax-flags 0 "apply PaX flags to rustc binaries (required for GRSecurity/PaX-patched kernels)"
valopt prefix "/usr/local" "set installation prefix"
@ -393,7 +394,7 @@ validate_opt
if [ $HELP -eq 1 ]
then
echo ""
echo
exit 0
fi
@ -421,6 +422,7 @@ else
fi
probe CFG_CLANG clang++
probe CFG_CCACHE ccache
probe CFG_GCC gcc
probe CFG_LD ld
probe CFG_VALGRIND valgrind
@ -439,6 +441,10 @@ then
probe CFG_ZCAT zcat
fi
step_msg "looking for target specific programs"
probe CFG_ADB adb
if [ ! -z "$CFG_PANDOC" ]
then
PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc ' |
@ -533,7 +539,7 @@ then
LLVM_VERSION=$($LLVM_CONFIG --version)
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"
;;
(*)
@ -551,11 +557,11 @@ then
CFG_CLANG_VERSION=$("$CFG_CLANG" \
--version \
| grep version \
| sed 's/.*\(version .*\)/\1/' \
| sed 's/.*\(version .*\)/\1/; s/.*based on \(LLVM .*\))/\1/' \
| cut -d ' ' -f 2)
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"
CFG_C_COMPILER="clang"
;;
@ -567,6 +573,16 @@ else
CFG_C_COMPILER="gcc"
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
CFG_PREFIX=${CFG_PREFIX%/}
@ -639,7 +655,7 @@ fi
step_msg "making directories"
for i in \
doc doc/core doc/std \
doc doc/std doc/extra \
dl tmp
do
make_dir $i
@ -661,12 +677,17 @@ make_dir rt
for t in $CFG_TARGET_TRIPLES
do
make_dir rt/$t
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
for s in 0 1 2 3
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
@ -691,6 +712,9 @@ do
# host lib dir
make_dir $h/stage$i/$CFG_LIBDIR
# host test dir
make_dir $h/stage$i/test
# target bin dir
make_dir $h/stage$i/$CFG_LIBDIR/rustc/$t/bin
@ -810,24 +834,37 @@ do
LLVM_TARGET="--target=$t"
# Disable unused LLVM features
LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs \
--enable-bindings=none --disable-threads \
--disable-pthreads"
LLVM_OPTS="$LLVM_DBG_OPTS --disable-docs --enable-bindings=none"
if [ "$CFG_C_COMPILER" = "clang" ]
then
case "$CFG_C_COMPILER" in
("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_CC_32="clang -m32"
LLVM_CXX_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_CC_32="gcc -m32"
LLVM_CXX_64="g++"
LLVM_CC_64="gcc"
fi
esac
LLVM_CFLAGS_32="-m32"
LLVM_CXXFLAGS_32="-m32"
@ -859,7 +896,7 @@ do
LDFLAGS=$LLVM_LDFLAGS
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 "$LLVM_FLAGS"
@ -924,6 +961,21 @@ then
putvar CFG_PAXCTL
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 ]
then
CFG_PANDOC=

View File

@ -1,13 +1,28 @@
The markdown docs are only generated by make when node is installed (use
`make doc`). If you don't have node installed you can generate them yourself.
Unfortunately there's no real standard for markdown and all the tools work
differently. pandoc is one that seems to work well.
Pandoc, a universal document converter, is required to generate docs as HTML
from Rust's source code. It's available for most platforms here:
http://johnmacfarlane.net/pandoc/installing.html
To generate an html version of a doc do something like:
pandoc --from=markdown --to=html --number-sections -o build/doc/rust.html doc/rust.md && git web--browse build/doc/rust.html
Node.js (http://nodejs.org/) is also required for generating HTML from
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:
http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown
A nice quick reference (for non-pandoc markdown) is at:
http://kramdown.rubyforge.org/quickref.html
http://kramdown.rubyforge.org/quickref.html

View File

@ -1,39 +1,78 @@
body {
padding: 1em;
margin: 0;
margin-bottom: 4em;
font-family: "Helvetica Neue", Helvetica, sans-serif;
background-color: white;
color: black;
line-height: 1.6em;
}
body {
padding: 1em 6em;
max-width: 60em;
padding: 1em 6em;
margin: 0;
margin-bottom: 4em;
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 12pt;
background-color: white;
color: black;
line-height: 1.6em;
min-width: 45em;
max-width: 60em;
}
h1 {
font-size: 20pt;
margin-top: 2em;
border-bottom: 1px solid silver;
line-height: 1.6em;
font-size: 24pt;
margin-top: 1.6em;
padding-left: 0.4em;
line-height: 1.6em;
background-color:#FFF2CE;
border-radius: 0.2em;
}
h2 {
font-size: 15pt;
margin-top: 2em;
font-size: 16pt;
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 {
margin: 1.1em 0;
padding: .4em .4em .4em 2em;
font-size: 120%;
margin-left: 1.1em;
padding: .4em .4em .4em .8em;
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 {
text-decoration: none;
color: rgb(0, 105, 214);
text-decoration: none;
color: rgb(0, 105, 214);
}
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 */
div.index ul {
padding-left: 1em;
}
}
ul {
margin-top: 0em
}
div.section.level3 {
margin-left: 1.0em;
}

View File

@ -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
[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
documented separately by extracting documentation attributes from their
source code.
[tutorial]: tutorial.html
[core]: core/index.html
[standard]: std/index.html
[extra]: extra/index.html
## Disclaimer
@ -301,10 +301,10 @@ num_lit : nonzero_dec [ dec_digit | '_' ] * num_suffix ?
num_suffix : int_suffix | float_suffix ;
int_suffix : 'u' int_suffix_size ?
| 'i' int_suffix_size ;
| 'i' int_suffix_size ? ;
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' ] ;
exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
dec_lit : [ dec_digit | '_' ] + ;
@ -441,10 +441,10 @@ expression context, the final namespace qualifier is omitted.
Two examples of paths with type arguments:
~~~~
# use core::hashmap::linear::LinearMap;
# use std::hashmap::HashMap;
# fn f() {
# 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
# }
~~~~
@ -618,7 +618,7 @@ each of which may have some number of [attributes](#attributes) attached to it.
~~~~~~~~ {.ebnf .gram}
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
@ -752,10 +752,11 @@ link_attr : ident '=' literal ;
~~~~~~~~
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
runtime linkage requirement to that `soname` is passed to the linker for
The external crate is resolved to a specific `soname` at compile time,
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
compiler's library path and matching the `link_attrs` provided in the
`use_decl` against any `#link` attributes that were declared on the external
@ -767,9 +768,9 @@ Three examples of `extern mod` declarations:
~~~~~~~~{.xfail-test}
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
@ -801,20 +802,15 @@ Use declarations support a number of convenient shortcuts:
An example of `use` declarations:
~~~~
use core::float::sin;
use core::str::{slice, to_upper};
use core::option::Some;
use std::float::sin;
use std::option::{Some, None};
fn main() {
// Equivalent to 'info!(core::float::sin(1.0));'
// Equivalent to 'info!(std::float::sin(1.0));'
info!(sin(1.0));
// Equivalent to 'info!(core::option::Some(1.0));'
info!(Some(1.0));
// Equivalent to
// 'info!(core::str::to_upper(core::str::slice("foo", 0, 1)));'
info!(to_upper(slice("foo", 0, 1)));
// Equivalent to 'info!(~[std::option::Some(1.0), std::option::None]);'
info!(~[Some(1.0), None]);
}
~~~~
@ -886,11 +882,11 @@ the function name.
~~~~ {.xfail-test}
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] {
let mut acc = ~[];
for seq.each |elt| { acc.push(f(elt)); }
for seq.iter().advance |elt| { acc.push(f(elt)); }
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 are part of Rust's foreign function interface,
providing the opposite functionality to [foreign modules](#foreign-modules).
Whereas foreign modules allow Rust code to call foreign code,
extern functions with bodies defined in Rust code _can be called by foreign code_.
They are defined in the same way as any other Rust function,
providing the opposite functionality to [external blocks](#external-blocks).
Whereas external blocks allow Rust code to call foreign code,
extern functions with bodies defined in Rust code _can be called by foreign
code_. They are defined in the same way as any other Rust function,
except that they have the `extern` modifier.
~~~
@ -1011,7 +1007,8 @@ let fptr: *u8 = new_vec;
~~~
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
@ -1295,7 +1292,7 @@ with matching types and type parameter counts.
An implementation can take type parameters,
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> { }
@ -1308,64 +1305,61 @@ impl Seq<bool> for u32 {
}
~~~~
### Foreign modules
### External blocks
~~~ {.ebnf .gram}
foreign_mod_item : "extern mod" ident '{' foreign_mod '} ;
foreign_mod : [ foreign_fn ] * ;
extern_block_item : "extern" '{' extern_block '} ;
extern_block : [ foreign_fn ] * ;
~~~
Foreign modules form the basis for Rust's foreign function interface. A
foreign module describes functions 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.
External blocks form the basis for Rust's foreign function interface.
Declarations in an external block describe symbols
in external, non-Rust libraries.
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]
extern mod c {
extern {
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.
The Rust compiler automatically translates between the Rust ABI and the foreign ABI.
Functions within external blocks may be called by Rust code,
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
that it will treat the module name as the name of a library to link to,
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 external
blocks.
A number of [attributes](#attributes) control the behavior of foreign
modules.
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
By default external blocks assume
that the library they are calling uses the standard C "cdecl" ABI.
Other ABIs may be specified using the `abi` attribute as in
~~~{.xfail-test}
// Interface to the Windows API
#[abi = "stdcall"]
extern mod kernel32 { }
extern { }
~~~
The `link_name` attribute allows the default library naming behavior to
be overridden by explicitly specifying the name of the library.
The `link_name` attribute allows the name of the library to be specified.
~~~{.xfail-test}
#[link_name = "crypto"]
extern mod mycrypto { }
extern { }
~~~
The `nolink` attribute tells the Rust compiler not to do any linking for the foreign module.
This is particularly useful for creating foreign
modules for libc, which tends to not follow standard library naming
conventions and is linked to all Rust programs anyway.
The `nolink` attribute tells the Rust compiler
not to do any linking for the external block.
This is particularly useful for creating external blocks for libc,
which tends to not follow standard library naming conventions
and is linked to all Rust programs anyway.
## Attributes
@ -1425,6 +1419,9 @@ names are effectively reserved. Some significant attributes include:
* The `test` attribute, for marking functions as unit tests.
* The `allow`, `warn`, `forbid`, and `deny` attributes, for controlling lint checks. Lint checks supported
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.
@ -1434,7 +1431,7 @@ Some primitive Rust operations are defined in Rust code,
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 `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}
#[lang="str_eq"]
@ -1468,9 +1465,9 @@ A complete list of the built-in language items follows:
`mul`
: Elements can be multiplied.
`div`
: Elements can be divided.
`mod`
: Elements have a modulo operation.
: Elements have a division operation.
`rem`
: Elements have a remainder operation.
`neg`
: Elements can be negated arithmetically.
`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
> 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
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
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)
values.
~~~~~~~~ {.tuple}
(0,);
(0f, 4.5f);
("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_.
~~~~
# use std::task;
# do task::spawn_unlinked {
([1, 2, 3, 4])[0];
@ -1841,25 +1884,25 @@ Binary operators expressions are given in terms of
#### Arithmetic operators
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.
The default meaning of the operators on standard types is given here.
`+`
: 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.
Calls the `sub` method on the `core::ops::Sub` trait.
Calls the `sub` method on the `std::ops::Sub` trait.
`*`
: Multiplication.
Calls the `mul` method on the `core::ops::Mul` trait.
Calls the `mul` method on the `std::ops::Mul` trait.
`/`
: Division.
Calls the `div` method on the `core::ops::Div` trait.
: Quotient.
Calls the `div` method on the `std::ops::Div` trait.
`%`
: Modulo (a.k.a. "remainder").
Calls the `modulo` method on the `core::ops::Modulo` trait.
: Remainder.
Calls the `rem` method on the `std::ops::Rem` trait.
#### Bitwise operators
@ -1870,19 +1913,19 @@ The default meaning of the operators on standard types is given here.
`&`
: And.
Calls the `bitand` method of the `core::ops::BitAnd` trait.
Calls the `bitand` method of the `std::ops::BitAnd` trait.
`|`
: Inclusive or.
Calls the `bitor` method of the `core::ops::BitOr` trait.
Calls the `bitor` method of the `std::ops::BitOr` trait.
`^`
: 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.
Calls the `shl` method of the `core::ops::Shl` trait.
Calls the `shl` method of the `std::ops::Shl` trait.
`>>`
: 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
@ -1903,22 +1946,22 @@ The default meaning of the operators on standard types is given here.
`==`
: Equal to.
Calls the `eq` method on the `core::cmp::Eq` trait.
Calls the `eq` method on the `std::cmp::Eq` trait.
`!=`
: Unequal to.
Calls the `ne` method on the `core::cmp::Eq` trait.
Calls the `ne` method on the `std::cmp::Eq` trait.
`<`
: Less than.
Calls the `lt` method on the `core::cmp::Ord` trait.
Calls the `lt` method on the `std::cmp::Ord` trait.
`>`
: 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.
Calls the `le` method on the `core::cmp::Ord` trait.
Calls the `le` method on the `std::cmp::Ord` trait.
`>=`
: 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
@ -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
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
@ -2106,11 +2121,11 @@ then the expression completes.
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 }
let x: int = add(1, 2);
let pi = from_str::<f32>("3.14");
let pi = FromStr::from_str::<f32>("3.14");
~~~~
### 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;
while i < 10 {
io::println("hello\n");
println("hello\n");
i = i + 1;
}
~~~~
@ -2186,7 +2201,7 @@ A loop expression denotes an infinite loop;
see [Continue expressions](#continue-expressions) for continue expressions.
~~~~~~~~{.ebnf .gram}
loop_expr : "loop" [ ident ':' ] '{' block '}';
loop_expr : [ lifetime ':' ] "loop" '{' block '}';
~~~~~~~~
A `loop` expression may optionally have a _label_.
@ -2197,7 +2212,7 @@ See [Break expressions](#break-expressions).
### Break expressions
~~~~~~~~{.ebnf .gram}
break_expr : "break" [ ident ];
break_expr : "break" [ lifetime ];
~~~~~~~~
A `break` expression has an optional `label`.
@ -2210,7 +2225,7 @@ but must enclose it.
### Continue expressions
~~~~~~~~{.ebnf .gram}
continue_expr : "loop" [ ident ];
continue_expr : "loop" [ lifetime ];
~~~~~~~~
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),
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;
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,
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,
to access a local flag that causes an early return in the caller.
In contrast to a `do` expression, a `for` expression is designed to work
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)
inside the `block` of a `for` 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.
Like `return` expressions, any [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
are rewritten inside `for` expressions, with a combination of local flag variables,
In addition, [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
are rewritten inside `for` expressions in the same way that `return` expressions are,
with a combination of local flag variables,
and early boolean-valued returns from the `block` function,
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.
@ -2304,11 +2323,13 @@ An example of a for loop over the contents of a vector:
~~~~
# type foo = int;
# 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];
for v.each |e| {
for v.iter().advance |e| {
bar(*e);
}
~~~~
@ -2316,6 +2337,7 @@ for v.each |e| {
An example of a for loop over a series of integers:
~~~~
# use std::uint;
# fn bar(b:uint) { }
for uint::range(0, 256) |i| {
bar(i);
@ -2372,9 +2394,9 @@ enum List<X> { Nil, Cons(X, @List<X>) }
let x: List<int> = Cons(10, @Cons(11, @Nil));
match x {
Cons(_, @Nil) => fail!(~"singleton list"),
Cons(_, @Nil) => fail!("singleton list"),
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
explicit using the ```copy``` keyword, changed to bind to a borrowed pointer by using the ```ref```
keyword, or to a mutable borrowed pointer using ```ref mut```, or the value can be moved into
the new binding using ```move```.
Patterns that bind variables default to binding to a copy or move of the matched value
(depending on the matched value's type).
This can be made explicit using the ```copy``` keyword,
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,
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
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
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.
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,
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.
@ -2778,6 +2801,7 @@ the vtable pointer for the `T` implementation of `R`, and the pointer value of `
An example of an object type:
~~~~~~~~
# use std::int;
trait Printable {
fn to_str(&self) -> ~str;
}
@ -2787,7 +2811,7 @@ impl Printable for int {
}
fn print(a: @Printable) {
io::println(a.to_str());
println(a.to_str());
}
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] {
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()));
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.
The kinds are:
`Const`
`Freeze`
: Types of this kind are deeply immutable;
they contain no mutable memory locations directly or indirectly via pointers.
`Owned`
`Send`
: Types of this kind can be safely sent between tasks.
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`
: 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).
@ -2858,7 +2882,7 @@ The kinds are:
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",
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`.
> **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,
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.
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,
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
`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`).
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
- 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.
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.
@ -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.
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.
@ -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,
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
@ -3251,6 +3275,28 @@ of runtime logging modules follows.
* `::rt::backtrace` Log a backtrace on task failure
* `::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
@ -3328,4 +3374,3 @@ Additional specific influences can be seen from the following languages:
* The typeclass system of Haskell.
* The lexical identifier rule of Python.
* The block syntax of Ruby.

137
doc/rustpkg.md Normal file
View 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.

View File

@ -42,14 +42,14 @@ point, but allocated in a different place:
~~~
# struct Point {x: float, y: float}
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
let shared_box : @Point = @Point {x: 5.0, y: 1.0};
let unique_box : ~Point = ~Point {x: 7.0, y: 9.0};
let managed_box : @Point = @Point {x: 5.0, y: 1.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
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
`shared_box` and `unique_box`. One option is to define a function that takes
compute the distance between `on_the_stack` and `managed_box`, or between
`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
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
@ -73,11 +73,11 @@ Now we can call `compute_distance()` in various ways:
~~~
# struct Point {x: float, y: float}
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
# let shared_box : @Point = @Point{x: 5.0, y: 1.0};
# let unique_box : ~Point = ~Point{x: 7.0, y: 9.0};
# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};
# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }
compute_distance(&on_the_stack, shared_box);
compute_distance(shared_box, unique_box);
compute_distance(&on_the_stack, managed_box);
compute_distance(managed_box, owned_box);
~~~
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
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
`@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
unique box to the callee.
of borrowing: in this case, the caller lends the contents of the managed or
owned box to the callee.
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
@ -155,7 +155,7 @@ 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_unique = ~Rectangle {origin: Point {x: 5f, y: 6f},
let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f},
size: Size {w: 3f, h: 4f}};
~~~
@ -168,7 +168,7 @@ operator. For example, I could write:
# struct Rectangle {origin: Point, size: Size}
# 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_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 }
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
Weve seen a few examples so far of borrowing heap boxes, both managed
and unique. Up till this point, weve glossed over issues of
and owned. Up till this point, weve glossed over issues of
safety. As stated in the introduction, at runtime a borrowed pointer
is simply a pointer, nothing more. Therefore, avoiding C's problems
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
it. It would violate memory safety for the box that was originally
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
> 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
process is called *rooting*.
# Borrowing unique boxes
# Borrowing owned boxes
The previous example demonstrated *rooting*, the process by which the
compiler ensures that managed boxes remain live for the duration of a
borrow. Unfortunately, rooting does not work for borrows of unique
boxes, because it is not possible to have two references to a unique
borrow. Unfortunately, rooting does not work for borrows of owned
boxes, because it is not possible to have two references to a owned
box.
For unique boxes, therefore, the compiler will only allow a borrow *if
the compiler can guarantee that the unique box will not be reassigned
For owned boxes, therefore, the compiler will only allow a borrow *if
the compiler can guarantee that the owned box will not be reassigned
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:
~~~
@ -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.
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
scope_. Therefore, a program like this is illegal (and would be
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
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
mutations:
@ -366,7 +366,7 @@ invalidate the pointer `y`.
# Borrowing and enums
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
case where the compiler must be very careful to ensure that pointers
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.
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
overwritten for the duration of the borrow. In fact, the compiler
would accept the example we gave earlier. The example is safe because
the shape pointer has type `&Shape`, which means "borrowed pointer to
immutable memory containing a `shape`". If, however, the type of that
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,
but otherwise it requires that the data reside in immutable memory.
# 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
borrowed pointer, then uses it within the same scope. It is also
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.
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 dont refer to a specific expression within `get_x()`,
but rather to some expression within the *caller of `get_x()`*. The
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
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
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

207
doc/tutorial-container.md Normal file
View 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());
~~~

View File

@ -2,255 +2,269 @@
# Introduction
Because Rust is a systems programming language, one of its goals is to
interoperate well with C code.
This tutorial will use the [snappy](https://code.google.com/p/snappy/)
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
go over it one piece at a time. This is a program that uses OpenSSL's
`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.
The following is a minimal example of calling a foreign function which will compile if snappy is
installed:
~~~~ {.xfail-test}
extern mod std;
use core::libc::c_uint;
use std::libc::size_t;
extern mod crypto {
fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8;
}
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));
}
#[link_args = "-lsnappy"]
extern {
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
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
to declare it. That is what this part of the program does:
Foreign functions are assumed to be unsafe so calls to them need to be wrapped with `unsafe {}` as a
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}
extern mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; }
~~~~
use std::libc::{c_int, size_t};
An `extern` module declaration containing function signatures introduces the
functions listed as _foreign functions_. Foreign functions differ from regular
Rust functions in that they are implemented in some other language (usually C)
and called through Rust's foreign function interface (FFI). An extern module
like this is called a foreign module, and implicitly tells the compiler to
link with a library that contains the listed foreign functions, and has the
same name as the module.
In this case, the Rust compiler changes the name `crypto` to a shared library
name in a platform-specific way (`libcrypto.so` on Linux, for example),
searches for the shared library with that name, and links the library into the
program. If you want the module to have a different name from the actual
library, you can use the `"link_name"` attribute, like:
~~~~ {.xfail-test}
#[link_name = "crypto"]
extern mod something {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
#[link_args = "-lsnappy"]
extern {
fn snappy_compress(input: *u8,
input_length: size_t,
compressed: *mut u8,
compressed_length: *mut size_t) -> c_int;
fn snappy_uncompress(compressed: *u8,
compressed_length: size_t,
uncompressed: *mut u8,
uncompressed_length: *mut size_t) -> c_int;
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
fn snappy_uncompressed_length(compressed: *u8,
compressed_length: size_t,
result: *mut size_t) -> c_int;
fn snappy_validate_compressed_buffer(compressed: *u8,
compressed_length: size_t) -> c_int;
}
~~~~
# 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
Most foreign code is C code, which usually uses the `cdecl` calling
convention, so that is what Rust uses by default when calling foreign
functions. Some foreign functions, most notably the Windows API, use other
calling conventions. Rust provides the `"abi"` attribute as a way to hint to
the compiler which calling convention to use:
Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
conventions. Rust provides the `abi` attribute as a way to hint to the compiler which calling
convention to use:
~~~~
#[cfg(target_os = "win32")]
#[abi = "stdcall"]
extern mod kernel32 {
#[link_name = "kernel32"]
extern {
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
}
~~~~
The `"abi"` attribute applies to a foreign module (it cannot be applied
to a single function within a module), and must be either `"cdecl"`
or `"stdcall"`. We may extend the compiler in the future to support other
The `abi` attribute applies to a foreign module (it cannot be applied to a single function within a
module), and must be either `"cdecl"` or `"stdcall"`. The compiler may eventually support other
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}
# extern mod crypto {
fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
# }
~~~~
Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
object. However, they should not be manually created because they are managed by internal
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
compiler has no way to check whether your declaration is correct, so
you have to be careful. If you get the number or types of the
arguments wrong, you're likely to cause a segmentation fault. Or,
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.
Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
`str` modules for working with C APIs. Strings are terminated with `\0` for interoperability with C,
but it should not be assumed because a slice will not always be nul-terminated. Instead, the
`str::as_c_str` function should be used.
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.

View File

@ -13,7 +13,8 @@ doing nothing otherwise:
~~~~
# enum t { special_a(uint), special_b(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 {
special_a(x) => { return x; }
_ => {}
@ -38,7 +39,8 @@ the pattern in the above code:
~~~~
# enum t { special_a(uint), special_b(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(
($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`
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)};
# 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(
($inp:expr, [ $($sp:ident)|+ ]) => (
match $inp {
@ -223,7 +226,7 @@ match x {
// complicated stuff goes here
return result + val;
},
_ => fail!(~"Didn't get good_2")
_ => fail!("Didn't get good_2")
}
}
_ => return 0 // default value
@ -265,7 +268,7 @@ macro_rules! biased_match (
biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
binds g1, val )
biased_match!((g1.body) ~ (good_2(result) )
else { fail!(~"Didn't get good_2") };
else { fail!("Didn't get good_2") };
binds result )
// complicated stuff goes here
return result + val;
@ -366,7 +369,7 @@ macro_rules! biased_match (
# fn f(x: t1) -> uint {
biased_match!(
(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 )
// complicated stuff goes here
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
intermediate states out, and passing the flag `--pretty expanded` as a
command-line argument to the compiler will show the result of expansion.

View File

@ -2,86 +2,77 @@
# Introduction
The designers of Rust designed the language from the ground up to support pervasive
and safe concurrency through lightweight, memory-isolated tasks and
message passing.
Rust provides safe concurrency through a combination
of lightweight, memory-isolated tasks and 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
_green threads_. The Rust runtime system schedules tasks cooperatively onto a
small number of operating system threads. Because tasks are significantly
Rust tasks are not the same as traditional threads: rather,
they are considered _green threads_, lightweight units of execution that the Rust
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
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
code (as a result of an explicit call to `fail!()`, an assertion failure, or
another invalid operation), the runtime system destroys the entire
In order to make efficient use of memory 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 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
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
particular, the type system guarantees that tasks cannot share mutable state
with each other. Tasks communicate with each other by transferring _owned_
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
While Rust's type system provides the building blocks needed for safe
and efficient tasks, all of the task functionality itself is implemented
in the core and standard libraries, which are still under development
and do not always present a consistent 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.
in the standard and extra libraries, which are still under development
and do not always present a consistent or complete interface.
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
* [`core::comm`] - The deprecated message passing API
* [`core::pipes`] - The new message passing infrastructure and API
* [`std::comm`] - Higher level messaging types based on `core::pipes`
* [`std::sync`] - More exotic synchronization tools, including locks
* [`std::arc`] - The ARC (atomic reference counted) type, for safely sharing
immutable data
* [`std::par`] - Some basic tools for implementing parallel algorithms
* [`std::task`] - All code relating to tasks and task scheduling,
* [`std::comm`] - The message passing interface,
* [`std::pipes`] - The underlying messaging infrastructure,
* [`extra::comm`] - Additional messaging types based on `std::pipes`,
* [`extra::sync`] - More exotic synchronization tools, including locks,
* [`extra::arc`] - The ARC (atomically reference counted) type,
for safely sharing immutable data,
* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time.
[`core::task`]: core/task.html
[`core::comm`]: core/comm.html
[`core::pipes`]: core/pipes.html
[`std::task`]: std/task.html
[`std::comm`]: std/comm.html
[`std::sync`]: std/sync.html
[`std::arc`]: std/arc.html
[`std::par`]: std/par.html
[`std::pipes`]: std/pipes.html
[`extra::comm`]: extra/comm.html
[`extra::sync`]: extra/sync.html
[`extra::arc`]: extra/arc.html
[`extra::future`]: extra/future.html
# Basics
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
calling the `spawn` function with a closure argument. `spawn` executes the
closure in the new task.
~~~~
# use core::io::println;
use core::task::spawn;
# use std::io::println;
# use std::task::spawn;
// Print something profound in a different task using a named function
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
concept that appears in the language semantics. Instead, Rust's type system
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.
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.
~~~
# use core::io::println;
# use core::task::spawn;
# use std::io::println;
# use std::task::spawn;
# fn generate_task_number() -> int { 0 }
// Generate some state locally
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.
~~~
# use core::io::print;
# use core::task::spawn;
# use std::io::print;
# use std::task::spawn;
# use std::int;
for int::range(0, 20) |child_task_number| {
do spawn {
@ -156,8 +148,8 @@ endpoint. Consider the following example of calculating two results
concurrently:
~~~~
use core::task::spawn;
use core::comm::{stream, Port, Chan};
# use std::task::spawn;
# use std::comm::{stream, Port, Chan};
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).
~~~~
# use core::comm::{stream, Chan, Port};
# use std::comm::{stream, Chan, Port};
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.
~~~~
# use core::task::spawn;
# use core::comm::stream;
# use std::task::spawn;
# use std::comm::stream;
# fn some_expensive_computation() -> int { 42 }
# let (port, chan) = stream();
do spawn || {
@ -208,7 +200,7 @@ computation, then waits for the child's result to arrive on the
port:
~~~~
# use core::comm::{stream};
# use std::comm::{stream};
# fn some_other_expensive_computation() {}
# let (port, chan) = stream::<int>();
# chan.send(0);
@ -223,8 +215,8 @@ example needed to compute multiple results across a number of tasks? The
following program is ill-typed:
~~~ {.xfail-test}
# use core::task::{spawn};
# use core::comm::{stream, Port, Chan};
# use std::task::{spawn};
# use std::comm::{stream, Port, Chan};
# fn some_expensive_computation() -> int { 42 }
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.
~~~
# use core::task::spawn;
use core::comm::{stream, SharedChan};
# use std::task::spawn;
# use std::comm::{stream, SharedChan};
# use std::uint;
let (port, chan) = stream();
let chan = SharedChan(chan);
let chan = SharedChan::new(chan);
for uint::range(0, 3) |init_val| {
// 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.
~~~
# use core::task::spawn;
# use core::comm::stream;
# use std::task::spawn;
# use std::comm::stream;
# use std::vec;
// Create a vector of ports, one for each child task
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
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 }
~~~
## 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
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.
~~~
# use core::task::spawn;
# use std::task::spawn;
# use std::task;
# fn do_some_work() { loop { task::yield() } }
# do task::try {
// Create a child task that fails
@ -330,13 +452,14 @@ field (representing a successful result) or an `Err` result (representing
termination with an error).
~~~
# use std::task;
# fn some_condition() -> bool { false }
# fn calculate_result() -> int { 0 }
let result: Result<int, ()> = do task::try {
if some_condition() {
calculate_result()
} else {
fail!(~"oops!");
fail!("oops!");
}
};
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
an `Error` result.
[`Result`]: core/result.html
[`Result`]: std/result.html
> ***Note:*** A failed task does not currently produce a useful error
> 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
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
it trips, indicates an unrecoverable logic error); in other cases you
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.
~~~
# use std::task;
# fn sleep_forever() { loop { task::yield() } }
# do task::try {
do task::spawn {
do task::spawn {
do spawn {
do spawn {
fail!(); // All three tasks will 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:
~~~
# use core::comm::{stream, Chan, Port};
# use core::task::{spawn, try};
# use std::comm::{stream, Chan, Port};
# use std::task::{spawn, try};
# use std::task;
# fn sleep_forever() { loop { task::yield() } }
# do task::try {
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:
~~~
# use std::task;
# fn sleep_forever() { loop { task::yield() } }
# fn wait_for_a_while() { for 1000.times { task::yield() } }
# 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_.
~~~
# use std::task;
# fn random() -> uint { 100 }
# fn sleep_for(i: uint) { for i.times { task::yield() } }
# do task::try::<()> {
@ -457,7 +584,7 @@ fail!();
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
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.
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:
~~~~
# use std::comm::DuplexStream;
# use extra::comm::DuplexStream;
# use std::uint;
fn stringifier(channel: &DuplexStream<~str, uint>) {
let mut value: uint;
loop {
@ -488,8 +616,9 @@ response itself is simply the stringified version of the received value,
Here is the code for the parent task:
~~~~
# use core::task::spawn;
# use std::comm::DuplexStream;
# use std::task::spawn;
# use std::uint;
# use extra::comm::DuplexStream;
# fn stringifier(channel: &DuplexStream<~str, uint>) {
# let mut value: uint;
# 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
one end of the communication channel. As a result, both parent and child can
send and receive data to and from the other.

File diff suppressed because it is too large Load Diff

View File

@ -7,4 +7,3 @@
</center>
</div>

View File

@ -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
rustc \- rust compiler
.SH SYNOPSIS
@ -33,6 +33,12 @@ Add a directory to the library search path
\fB\-\-lib\fR
Compile a library crate
.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
List the symbols defined by a library crate
.TP
@ -48,6 +54,11 @@ Write output to <filename>
\fB\-\-opt\-level\fR LEVEL
Optimize with possible levels 0-3
.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
Write output to compiler-chosen filename in <dir>
.TP
@ -77,6 +88,12 @@ Target triple cpu-manufacturer-kernel[-os] to compile for (see
http://sources.redhat.com/autobook/autobook/autobook_17.html
for detail)
.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
Print 'lint' options and default settings
.TP
@ -94,56 +111,6 @@ Set lint forbidden
.TP
\fB\-Z\fR FLAG
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
\fB\-v\fR, \fB\-\-version\fR
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.
.SH "COPYRIGHT"
This work is licensed under MIT-like terms. See \fBLICENSE.txt\fR
in the rust source distribution.
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR
file in the rust source distribution.

View File

@ -20,10 +20,10 @@ CLEAN_STAGE_RULES = \
clean$(stage)_T_$(target)_H_$(host))))
CLEAN_LLVM_RULES = \
$(foreach target, $(CFG_TARGET_TRIPLES), \
$(foreach target, $(CFG_HOST_TRIPLES), \
clean-llvm$(target))
.PHONY: clean clean-all clean-misc
.PHONY: clean clean-all clean-misc 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 -Rf $(DOCS)
$(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 $(foreach ext, \
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):
$(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))/serializer$(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))/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_LIBRUSTDOC_$(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_EXTRALIB_$(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_LIBRUSTI_$(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))/$(EXTRALIB_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))/$(LIBFUZZER_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))/$(LIBRUSTI_GLOB_$(2))
@ -101,27 +98,24 @@ define CLEAN_TARGET_STAGE_N
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))/fuzzer$(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))/rustdoc$(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 $$(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_LIBRUSTDOC_$(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_EXTRALIB_$(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_LIBRUSTI_$(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))/$(EXTRALIB_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))/$(LIBFUZZER_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))/$(LIBRUSTI_GLOB_$(2))

View File

@ -18,6 +18,7 @@ PKG_FILES := \
$(S)COPYRIGHT \
$(S)LICENSE-APACHE \
$(S)LICENSE-MIT \
$(S)AUTHORS.txt \
$(S)README.md \
$(S)configure $(S)Makefile.in \
$(S)man \
@ -31,10 +32,9 @@ PKG_FILES := \
librustc \
compiletest \
etc \
libfuzzer \
libcore \
libsyntax \
libextra \
libstd \
libsyntax \
rt \
librustdoc \
rustllvm \
@ -57,7 +57,7 @@ LICENSE.txt: $(S)COPYRIGHT $(S)LICENSE-APACHE $(S)LICENSE-MIT
cp $< $@
$(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: $@)
$(Q)"$(CFG_ISCC)" $<
endif

View File

@ -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
@$(call E, cp: $@)
@ -34,6 +27,18 @@ doc/manual.css: manual.css
@$(call E, cp: $@)
$(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
doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
@$(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 \
--include-before-body=doc/version_info.html \
--output=$@
endif
ifeq ($(CFG_PDFLATEX),)
$(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
DOCS += doc/rust.tex
doc/rust.tex: rust.md doc/version.md
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js $< | \
@ -70,23 +64,19 @@ doc/rust.tex: rust.md doc/version.md
--from=markdown --to=latex \
--output=$@
doc/rust.pdf: doc/rust.tex
@$(call E, pdflatex: $@)
$(Q)$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$<
endif
endif
endif
######################################################################
# Node (tutorial related)
######################################################################
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting doc/tutorial.html)
else
DOCS += doc/rustpkg.html
doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.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 \
--css=manual.css \
--include-before-body=doc/version_info.html \
--output=$@
DOCS += doc/tutorial.html
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 \
--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
doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css
@$(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 \
--output=$@
endif
endif
ifeq ($(CFG_PDFLATEX),)
$(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)
@ -163,7 +183,7 @@ endif
######################################################################
# Rustdoc (libcore/std)
# Rustdoc (libstd/extra)
######################################################################
ifeq ($(CFG_PANDOC),)
@ -189,8 +209,8 @@ doc/$(1)/rust.css: rust.css
DOCS += doc/$(1)/index.html
endef
$(eval $(call libdoc,core,$(CORELIB_CRATE),$(CORELIB_INPUTS)))
$(eval $(call libdoc,std,$(STDLIB_CRATE),$(STDLIB_INPUTS)))
$(eval $(call libdoc,extra,$(EXTRALIB_CRATE),$(EXTRALIB_INPUTS)))
endif

View File

@ -28,8 +28,10 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(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: $$@)
$$(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_RUNTIME_$(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: $$@)
$$(Q)cp $$< $$@
$$(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)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(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: $$@)
$$(Q)cp $$< $$@
$$(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))/$(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: $$@)
$$(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)): \
$$(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: $$@)
$$(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)) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(HLIB$(2)_H_$(4))/libcore.rlib: \
$$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, 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: \
$$(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: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/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))/$$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/libextra.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(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: $$@)
$$(Q)cp $$< $$@
$$(HBIN$(2)_H_$(4))/:
mkdir -p $$@
ifneq ($(CFG_LIBDIR),bin)
$$(HLIB$(2)_H_$(4))/:
mkdir -p $$@
endif
endef
$(foreach t,$(CFG_HOST_TRIPLES), \

View File

@ -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))
$$(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)),$$(CORELIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB, \
$$(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)
endef
@ -64,10 +64,10 @@ define INSTALL_HOST_N
install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(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)),$$(CORELIB_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB, \
$$(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)),$$(LIBRUSTC_GLOB_$(1)))
$$(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),rusti$(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),$(EXTRALIB_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),$(LIBRUSTI_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_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(S)/man, \
@ -139,8 +141,8 @@ uninstall:
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
$(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,$(EXTRALIB_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,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
@ -152,3 +154,76 @@ uninstall:
done
$(Q)rm -Rf $(PHL)/rustc
$(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

View File

@ -11,7 +11,7 @@
# Create variables HOST_<triple> containing the host part
# 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.
define DEF_HOST_VAR
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
# has a frame pointer and the stack walker can understand it. Turning off
# 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
# up in the right place. On other platforms, it automatically gets
@ -105,10 +105,35 @@ ifeq ($(CFG_C_COMPILER),gcc)
ifeq ($(origin CPP),default)
CPP=gcc
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
CFG_ERR := $(error please try on a system with gcc or clang)
endif
endif
endif
endif
# 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_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64
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_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
@ -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_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32
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_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-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_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_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_PRE_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_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386
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_PRE_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=
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
CC_i686-pc-mingw32=$(CC)
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_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
CFG_INSTALL_NAME_i686-pc-mingw32 =
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_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_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_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-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_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_WINDOWSY_x86_64-unknown-freebsd :=
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_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
CFG_COMPILE_C_$(1) = $$(CC_$(1)) \

View File

@ -12,12 +12,11 @@
ifdef PPFILES
PP_INPUTS_FILTERED := $(wildcard $(PPFILES))
else
PP_INPUTS = $(wildcard $(addprefix $(S)src/libcore/,*.rs */*.rs)) \
$(wildcard $(addprefix $(S)src/libstd/,*.rs */*.rs)) \
PP_INPUTS = $(wildcard $(addprefix $(S)src/libstd/,*.rs */*.rs)) \
$(wildcard $(addprefix $(S)src/libextra/,*.rs */*.rs)) \
$(wildcard $(addprefix $(S)src/rustc/,*.rs */*.rs */*/*.rs)) \
$(wildcard $(S)src/test/*/*.rs \
$(S)src/test/*/*/*.rs) \
$(wildcard $(S)src/fuzzer/*.rs) \
$(wildcard $(S)src/rustpkg/*.rs) \
$(wildcard $(S)src/rusti/*.rs) \
$(wildcard $(S)src/rust/*.rs)

165
mk/rt.mk
View File

@ -1,32 +1,37 @@
# This is a procedure to define the targets for building
# the runtime.
# the runtime.
#
# Argument 1 is the target triple.
#
# This is not really the right place to explain this, but
# 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
# will be defined once and then expanded with different
# 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
# is that the substitution would occur when the CALL occurs,
# I believe. The problem is that the automatic variables $< and $@
# 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
# will then be evaluated, and all will work as you like.
#
# Reader beware, this explanantion could be wrong, but it seems to
# fit the experimental data (i.e., I was able to get the system
# working under these assumptions).
# fit the experimental data (i.e., I was able to get the system
# working under these assumptions).
# Hack for passing flags into LIBUV, see below.
LIBUV_FLAGS_i386 = -m32 -fPIC
LIBUV_FLAGS_x86_64 = -m64 -fPIC
ifeq ($(OSTYPE_$(1)), linux-androideabi)
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
# features in libuv and the runtime as possible, to ease portability.
@ -36,14 +41,28 @@ ifneq ($(strip $(findstring snap,$(MAKECMDGOALS))),)
SNAP_DEFINES=-DRUST_SNAPSHOT
endif
define DEF_RUNTIME_TARGETS
######################################################################
# 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/lock_and_signal.cpp \
rt/sync/rust_thread.cpp \
@ -75,72 +94,75 @@ RUNTIME_CXXS_$(1) := \
rt/boxed_region.cpp \
rt/arch/$$(HOST_$(1))/context.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 \
rt/arch/$$(HOST_$(1))/ccall.S \
rt/arch/$$(HOST_$(1))/record_sp.S
RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
rt/arch/$$(HOST_$(1))/ccall.S \
rt/arch/$$(HOST_$(1))/record_sp.S
ifeq ($$(CFG_WINDOWSY_$(1)), 1)
LIBUV_OSTYPE_$(1) := win
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
LIBUV_OSTYPE_$(1)_$(2) := win
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)
LIBUV_OSTYPE_$(1) := mac
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
LIBUV_OSTYPE_$(1)_$(2) := mac
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)
LIBUV_OSTYPE_$(1) := unix/freebsd
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
LIBUV_OSTYPE_$(1)_$(2) := unix/freebsd
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)
LIBUV_OSTYPE_$(1) := unix/android
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
LIBUV_OSTYPE_$(1)_$(2) := unix/android
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
LIBUV_OSTYPE_$(1) := unix/linux
LIBUV_LIB_$(1) := rt/$(1)/libuv/libuv.a
LIBUV_OSTYPE_$(1)_$(2) := unix/linux
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
RUNTIME_DEF_$(1) := rt/rustrt$(CFG_DEF_SUFFIX_$(1))
RUNTIME_INCS_$(1) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
RUNTIME_DEF_$(1)_$(2) := rt/rustrt$(CFG_DEF_SUFFIX_$(1))
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/linenoise \
-I $$(S)src/libuv/include
RUNTIME_OBJS_$(1) := $$(RUNTIME_CXXS_$(1):rt/%.cpp=rt/$(1)/%.o) \
$$(RUNTIME_CS_$(1):rt/%.c=rt/$(1)/%.o) \
$$(RUNTIME_S_$(1):rt/%.S=rt/$(1)/%.o)
ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1))
RUNTIME_OBJS_$(1)_$(2) := $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=rt/$(1)/stage$(2)/%.o) \
$$(RUNTIME_CS_$(1)_$(2):rt/%.c=rt/$(1)/stage$(2)/%.o) \
$$(RUNTIME_S_$(1)_$(2):rt/%.S=rt/$(1)/stage$(2)/%.o)
ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
MORESTACK_OBJ_$(1) := rt/$(1)/arch/$$(HOST_$(1))/morestack.o
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1))
MORESTACK_OBJ_$(1)_$(2) := rt/$(1)/stage$(2)/arch/$$(HOST_$(1))/morestack.o
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
RUNTIME_LIBS_$(1) := $$(LIBUV_LIB_$(1))
rt/$(1)/%.o: rt/%.cpp $$(MKFILE_DEPS)
rt/$(1)/stage$(2)/%.o: rt/%.cpp $$(MKFILE_DEPS)
@$$(call E, compile: $$@)
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
$$(SNAP_DEFINES)) $$<
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
$$(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: $$@)
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)) \
$$(SNAP_DEFINES)) $$<
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
$$(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))
@$$(call E, compile: $$@)
$$(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: $$@)
$$(Q)$(AR_$(1)) rcs $$@ $$<
rt/$(1)/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)) $$(MKFILE_DEPS) \
$$(RUNTIME_DEF_$(1)) \
$$(RUNTIME_LIBS_$(1))
rt/$(1)/stage$(2)/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) \
$$(RUNTIME_DEF_$(1)_$(2)) $$(LIBUV_LIB_$(1)_$(2))
@$$(call E, link: $$@)
$$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)) \
$$(CFG_GCCISH_POST_LIB_FLAGS_$(1)) $$(RUNTIME_LIBS_$(1)) \
$$(CFG_LIBUV_LINK_FLAGS_$(1)),$$(RUNTIME_DEF_$(1)),$$(CFG_RUNTIME_$(1)))
$$(Q)$$(call CFG_LINK_CXX_$(1),$$@, $$(RUNTIME_OBJS_$(1)_$(2)) \
$$(CFG_GCCISH_POST_LIB_FLAGS_$(1)) $$(LIBUV_LIB_$(1)_$(2)) \
$$(CFG_LIBUV_LINK_FLAGS_$(1)),$$(RUNTIME_DEF_$(1)_$(2)),$$(CFG_RUNTIME_$(1)))
# 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
@ -159,31 +181,57 @@ endif
# XXX: Shouldn't need platform-specific conditions here
ifdef CFG_WINDOWSY_$(1)
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
$$(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 \
V=$$(VERBOSE)
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \
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))" \
BUILDTYPE=Release \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
host=android OS=linux \
V=$$(VERBOSE)
else
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
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))" \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
V=$$(VERBOSE)
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.
@ -219,5 +267,6 @@ endif
endef
# Instantiate template for all stages
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(eval $(call DEF_RUNTIME_TARGETS,$(target))))
$(foreach stage,$(STAGES), \
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))

View File

@ -22,7 +22,7 @@ LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
-iquote llvm/$(1)/include
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))

View File

@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \
$(S)src/etc/get-snapshot.py $(MKFILE_DEPS)
@$(call E, fetch: $@)
# 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
$(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)
ifdef CFG_ENABLE_PAX_FLAGS
@$(call E, apply PaX flags: $@)
@"$(CFG_PAXCTL)" -cm "$@"
endif
endif
endif
$(Q)touch $@
# 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))
$(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))
$(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))
$(Q)touch $@
@ -58,16 +58,16 @@ $$(HLIB0_H_$(1))/$(CFG_RUNTIME_$(1)): \
@$$(call E, 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)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_STDLIB_$(1))
@$$(call E, cp: $$@)
$$(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)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1))
@$$(call E, cp: $$@)

View File

@ -8,6 +8,20 @@
# option. This file may not be copied, modified, or distributed
# 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
# for all stage/target architecture combinations. The arguments:
# $(1) is the stage
@ -18,33 +32,38 @@
define TARGET_STAGE_N
$$(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: $$@)
$$(Q)cp $$< $$@
$$(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: $$@)
$$(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)): \
$$(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: $$@)
$$(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)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
$$(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: $$@)
$$(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)),)
$$(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: $$@)
$$(Q)cp $$< $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): CFG_COMPILER_TRIPLE = $(2)
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
$$(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: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
$$(DRIVER_CRATE) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3))
$$(DRIVER_CRATE) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \
| $$(TBIN$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$<
ifdef CFG_ENABLE_PAX_FLAGS
@ -75,6 +98,14 @@ endif
endif
$$(TBIN$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
ifneq ($(CFG_LIBDIR),bin)
$$(TLIB$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
endif
endef
# In principle, each host can build each target:

View File

@ -14,7 +14,7 @@
######################################################################
# 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_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
@ -92,6 +92,51 @@ endef
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(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
@ -111,7 +156,7 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
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
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
@ -179,9 +224,9 @@ tidy:
$(Q)find $(S)src/etc -name '*.py' \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(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) \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
endif
@ -244,58 +289,59 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
define TEST_RUNNER
# If NO_REBUILD is set then break the dependencies on std so we can
# test crates without rebuilding core and std first
# If NO_REBUILD is set then break the dependencies on extra so we can
# test crates without rebuilding std and extra first
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
STDTESTDEP_$(1)_$(2)_$(3) =
endif
$(3)/test/coretest.stage$(1)-$(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)): \
$(3)/stage$(1)/test/stdtest-$(2)$$(X_$(2)): \
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
@$$(call E, compile_and_link: $$@)
$$(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) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
@$$(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))
$$(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: $$<)
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(2),$(3)) $$(TESTARGS) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
&& touch $$@
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 target,$(CFG_TARGET_TRIPLES), \
$(foreach stage,$(STAGES), \
$(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)) \
--aux-base $$(S)src/test/auxiliary/ \
--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)" \
$$(CTEST_TESTARGS)
@ -454,7 +545,7 @@ ifeq ($$(CTEST_DISABLE_$(4)),)
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(TEST_SREQ$(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)) \
$$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
@ -465,7 +556,7 @@ else
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(TEST_SREQ$(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)))
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)): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
$$(PRETTY_DEPS_$(4))
@$$(call E, run pretty-rpass: $$<)
@$$(call E, run pretty-rpass [$(2)]: $$<)
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(PRETTY_ARGS$(1)-T-$(2)-H-$(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)): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
doc-$(4)-extract$(3)
@$$(call E, run doc-$(4): $$<)
@$$(call E, run doc-$(4) [$(2)]: $$<)
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \
@ -583,7 +674,7 @@ TEST_GROUPS = \
perf \
debuginfo \
doc \
$(foreach docname,$(DOC_TEST_NAMES),$(docname)) \
$(foreach docname,$(DOC_TEST_NAMES),doc-$(docname)) \
pretty \
pretty-rpass \
pretty-rpass-full \
@ -709,4 +800,3 @@ endef
$(foreach host,$(CFG_HOST_TRIPLES), \
$(eval $(call DEF_CHECK_FAST_FOR_H,$(host))))

View File

@ -11,61 +11,43 @@
# Rules for non-core tools built with the compiler, both for target
# 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
COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rc
COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*rs)
COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rs
COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*.rs)
# Rustpkg, the package manager and build system
RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rc
RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*rs)
RUSTPKG_LIB := $(S)src/librustpkg/rustpkg.rs
RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*.rs)
# 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)
# 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)
# 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)
# FIXME: These are only built for the host arch. Eventually we'll
# have tools that need to built for other targets.
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)): \
$$(COMPILETEST_CRATE) $$(COMPILETEST_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_STDLIB_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \
$$(RUSTPKG_LIB) $$(RUSTPKG_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_EXTRALIB_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
@$$(call E, compile_and_link: $$@)
$$(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)): \
$$(RUSTDOC_LIB) $$(RUSTDOC_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_EXTRALIB_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
@$$(call E, compile_and_link: $$@)
$$(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)): \
$$(RUSTI_LIB) $$(RUSTI_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_EXTRALIB_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4))
@$$(call E, compile_and_link: $$@)
$$(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)): \
$$(RUST_LIB) $$(RUST_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_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))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
@ -125,27 +110,6 @@ endef
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)): \
$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)) \
$$(HSREQ$(2)_H_$(4))
@ -227,7 +191,8 @@ $(foreach host,$(CFG_HOST_TRIPLES), \
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(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,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), \
$(eval $(call TOOLS_STAGE_N_HOST,0,1,$(host),$(host))) \

View File

@ -4,8 +4,8 @@ Source layout:
librustc/ The self-hosted compiler
libcore/ The core library (imported and linked by default)
libstd/ The standard library (slightly more peripheral code)
libstd/ The standard library (imported and linked by default)
libextra/ The "extras" library (slightly more peripheral code)
libsyntax/ The Rust parser and pretty-printer
rt/ The runtime system

View File

@ -66,6 +66,18 @@ pub struct config {
// Run tests using the new runtime
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
verbose: bool

View File

@ -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:

View 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()) })
}

View File

@ -11,8 +11,6 @@
use core::prelude::*;
use core::io;
use core::io::ReaderUtil;
use core::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;
while !rdr.eof() {
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;
}
return error_patterns;
}
fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] {
unsafe {
let error_tag = ~"//~";
let mut idx;
match str::find_str(line, error_tag) {
None => return ~[],
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}];
let error_tag = ~"//~";
let mut idx;
match line.find_str(error_tag) {
None => return ~[],
Some(nn) => { idx = (nn as uint) + error_tag.len(); }
}
// "//~^^^ 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}];
}

View File

@ -10,13 +10,11 @@
use core::prelude::*;
use common;
use common::config;
use common;
use core::io::ReaderUtil;
use core::io;
use core::os;
use core::str;
pub struct TestProps {
// 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);
}
for parse_aux_build(ln).each |ab| {
aux_builds.push(*ab);
match parse_aux_build(ln) {
Some(ab) => { aux_builds.push(ab); }
None => {}
}
for parse_exec_env(ln).each |ee| {
exec_env.push(*ee);
match parse_exec_env(ln) {
Some(ee) => { exec_env.push(ee); }
None => {}
}
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 {
let mut found = false;
pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
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 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 {
~"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
// module or function. This doesn't seem to be an optimization
// with a warm page cache. Maybe with a cold one.
if str::starts_with(ln, ~"fn")
|| str::starts_with(ln, ~"mod") {
if ln.starts_with("fn") || ln.starts_with("mod") {
return false;
} else { if !(it(ln)) { return false; } }
}
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")
}
fn parse_aux_build(line: ~str) -> Option<~str> {
fn parse_aux_build(line: &str) -> Option<~str> {
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")
}
fn parse_debugger_cmd(line: ~str) -> Option<~str> {
fn parse_debugger_cmd(line: &str) -> Option<~str> {
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")
}
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| {
// nv is either FOO or FOO=BAR
let mut strs = ~[];
for str::each_splitn_char(*nv, '=', 1u) |s| { strs.push(s.to_owned()); }
let mut strs: ~[~str] = nv.splitn_iter('=', 1).transform(|s| s.to_owned()).collect();
match strs.len() {
1u => (strs[0], ~""),
2u => (strs[0], strs[1]),
n => fail!(fmt!("Expected 1 or 2 strings, not %u", n))
1u => (strs.pop(), ~""),
2u => {
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") {
Some(s) => Some(Path(s)),
None => {
if parse_name_directive(line, ~"pp-exact") {
if parse_name_directive(line, "pp-exact") {
Some(testfile.file_path())
} else {
None
@ -165,22 +166,20 @@ fn parse_pp_exact(line: ~str, testfile: &Path) -> Option<Path> {
}
}
fn parse_name_directive(line: ~str, directive: ~str) -> bool {
str::contains(line, directive)
fn parse_name_directive(line: &str, directive: &str) -> bool {
line.contains(directive)
}
fn parse_name_value_directive(line: ~str,
fn parse_name_value_directive(line: &str,
directive: ~str) -> Option<~str> {
unsafe {
let keycolon = directive + ~":";
match str::find_str(line, keycolon) {
Some(colon) => {
let value = str::slice(line, colon + str::len(keycolon),
str::len(line)).to_owned();
debug!("%s: %s", directive, value);
Some(value)
}
None => None
let keycolon = directive + ":";
match line.find_str(keycolon) {
Some(colon) => {
let value = line.slice(colon + keycolon.len(),
line.len()).to_owned();
debug!("%s: %s", directive, value);
Some(value)
}
None => None
}
}

View File

@ -10,30 +10,25 @@
use core::prelude::*;
use core::io::{ReaderUtil, WriterUtil};
use core::io;
use core::libc::c_int;
use core::os;
use core::run::spawn_process;
use core::run;
use core::str;
use core::task;
#[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();
// Make sure we include the aux directory in the path
assert!(prog.ends_with(~".exe"));
let aux_path = prog.slice(0u, prog.len() - 4u) + ~".libaux";
assert!(prog.ends_with(".exe"));
let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux";
env = do vec::map(env) |pair| {
let (k,v) = *pair;
if k == ~"PATH" { (~"PATH", v + ~";" + lib_path + ~";" + aux_path) }
env = do env.map() |pair| {
let (k,v) = copy *pair;
if k == ~"PATH" { (~"PATH", v + ";" + lib_path + ";" + aux_path) }
else { (k,v) }
};
if str::ends_with(prog, ~"rustc.exe") {
if prog.ends_with("rustc.exe") {
env.push((~"RUST_THREADS", ~"1"));
}
return env;
@ -42,87 +37,35 @@ fn target_env(lib_path: ~str, prog: ~str) -> ~[(~str,~str)] {
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[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,
prog: ~str,
args: ~[~str],
pub fn run(lib_path: &str,
prog: &str,
args: &[~str],
env: ~[(~str, ~str)],
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);
os::close(pipe_out.out);
os::close(pipe_err.out);
if pid == -1i32 {
os::close(pipe_in.out);
os::close(pipe_out.in);
os::close(pipe_err.in);
fail!();
let env = env + target_env(lib_path, prog);
let mut proc = run::Process::new(prog, args, run::ProcessOptions {
env: Some(env.slice(0, env.len())),
dir: None,
in_fd: None,
out_fd: None,
err_fd: None
});
for input.iter().advance |input| {
proc.input().write_str(*input);
}
let output = proc.finish_with_output();
writeclose(pipe_in.out, input);
let p = comm::PortSet();
let ch = p.chan();
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;
Result {
status: output.status,
out: str::from_bytes(output.output),
err: str::from_bytes(output.error)
}
}

View File

@ -22,57 +22,55 @@ use procsrv;
use util;
use util::logv;
use core::io::WriterUtil;
use core::io;
use core::os;
use core::str;
use core::uint;
use core::vec;
pub fn run(config: config, testfile: ~str) {
if config.verbose {
// 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);
debug!("running %s", testfile.to_str());
let props = load_props(&testfile);
debug!("loaded props");
match config.mode {
mode_compile_fail => run_cfail_test(config, props, &testfile),
mode_run_fail => run_rfail_test(config, props, &testfile),
mode_run_pass => run_rpass_test(config, props, &testfile),
mode_pretty => run_pretty_test(config, props, &testfile),
mode_debug_info => run_debuginfo_test(config, props, &testfile)
mode_compile_fail => run_cfail_test(&config, &props, &testfile),
mode_run_fail => run_rfail_test(&config, &props, &testfile),
mode_run_pass => run_rpass_test(&config, &props, &testfile),
mode_pretty => run_pretty_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);
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);
if !expected_errors.is_empty() {
if !props.error_patterns.is_empty() {
fatal(~"both error pattern and expected errors specified");
}
check_expected_errors(expected_errors, testfile, ProcRes);
check_expected_errors(expected_errors, testfile, &ProcRes);
} 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 = compile_test(config, props, testfile);
if ProcRes.status != 0 {
fatal_ProcRes(~"compilation failed!", ProcRes);
fatal_ProcRes(~"compilation failed!", &ProcRes);
}
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
static valgrind_err: int = 100;
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);
check_error_patterns(props, testfile, ProcRes);
match config.target {
~"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
static rust_err: int = 101;
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 {
let mut ProcRes = compile_test(config, props, testfile);
if ProcRes.status != 0 {
fatal_ProcRes(~"compilation failed!", ProcRes);
fatal_ProcRes(~"compilation failed!", &ProcRes);
}
ProcRes = exec_compiled_test(config, props, testfile);
if ProcRes.status != 0 {
fatal_ProcRes(~"test run failed!", ProcRes);
fatal_ProcRes(~"test run failed!", &ProcRes);
}
} 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() {
logv(config, ~"testing for exact 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;
while round < rounds {
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 {
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;
}
let mut expected =
match props.pp_exact {
Some(file) => {
let filepath = testfile.dir_path().push_rel(&file);
Some(ref file) => {
let filepath = testfile.dir_path().push_rel(file);
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() {
// Now we have to care about line endings
let cr = ~"\r";
actual = str::replace(actual, cr, ~"");
expected = str::replace(expected, cr, ~"");
actual = actual.replace(cr, "");
expected = expected.replace(cr, "");
}
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);
if ProcRes.status != 0 {
fatal_ProcRes(~"pretty-printed source does not typecheck", ProcRes);
fatal_ProcRes(~"pretty-printed source does not typecheck", &ProcRes);
}
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),
~[], config.compile_lib_path, Some(src))
}
fn make_pp_args(config: config, _testfile: &Path) -> ProcArgs {
let prog = config.rustc_path;
fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
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 {
error(~"pretty-printed source does not match expected source");
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 {
compose_and_run_compiler(
config, props, testfile,
make_typecheck_args(config, props, testfile),
Some(src))
let args = make_typecheck_args(config, props, testfile);
compose_and_run_compiler(config, props, testfile, args, Some(src))
}
fn make_typecheck_args(config: config, props: TestProps, testfile: &Path) -> ProcArgs {
let prog = config.rustc_path;
fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
let mut args = ~[~"-",
~"--no-trans", ~"--lib",
~"-L", config.build_base.to_str(),
~"-L",
aux_output_dir_name(config, testfile).to_str()];
args += split_maybe_args(config.rustcflags);
args += split_maybe_args(props.compile_flags);
return ProcArgs {prog: prog.to_str(), args: args};
args.push_all_move(split_maybe_args(&config.rustcflags));
args.push_all_move(split_maybe_args(&props.compile_flags));
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
let config = match config.rustcflags {
Some(flags) => config {
rustcflags: Some(str::replace(flags, ~"-O", ~"")),
.. config
let mut config = match config.rustcflags {
Some(ref flags) => config {
rustcflags: Some(flags.replace("-O", "")),
.. 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)
let mut ProcRes = compile_test(config, props, testfile);
if ProcRes.status != 0 {
fatal_ProcRes(~"compilation failed!", ProcRes);
fatal_ProcRes(~"compilation failed!", &ProcRes);
}
// write debugger script
let script_str = str::append(str::connect(props.debugger_cmds, "\n"),
~"\nquit\n");
let script_str = cmds.append("\nquit\n");
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
#[cfg(windows)]
fn debugger() -> ~str { ~"gdb.exe" }
#[cfg(unix)]
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",
~"-command=" + debugger_script.to_str(),
make_exe_name(config, testfile).to_str()];
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 {
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 {
// check if each line in props.check_lines appears in the
// output (in order)
let mut i = 0u;
for str::each_line(ProcRes.stdout) |line| {
if props.check_lines[i].trim() == line.trim() {
for ProcRes.stdout.line_iter().advance |line| {
if check_lines[i].trim() == line.trim() {
i += 1u;
}
if i == num_check_lines {
@ -278,15 +287,15 @@ fn run_debuginfo_test(config: config, props: TestProps, testfile: &Path) {
}
if i != num_check_lines {
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,
ProcRes: ProcRes) {
if vec::is_empty(props.error_patterns) {
ProcRes: &ProcRes) {
if props.error_patterns.is_empty() {
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_pat = props.error_patterns[next_err_idx];
let mut next_err_pat = &props.error_patterns[next_err_idx];
let mut done = false;
for str::each_line(ProcRes.stderr) |line| {
if str::contains(line, next_err_pat) {
debug!("found error pattern %s", next_err_pat);
for ProcRes.stderr.line_iter().advance |line| {
if line.contains(*next_err_pat) {
debug!("found error pattern %s", *next_err_pat);
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");
done = true;
break;
}
next_err_pat = props.error_patterns[next_err_idx];
next_err_pat = &props.error_patterns[next_err_idx];
}
}
if done { return; }
let missing_patterns =
vec::slice(props.error_patterns, next_err_idx,
vec::len(props.error_patterns));
if vec::len(missing_patterns) == 1u {
props.error_patterns.slice(next_err_idx, props.error_patterns.len());
if missing_patterns.len() == 1u {
fatal_ProcRes(fmt!("error pattern '%s' not found!",
missing_patterns[0]), ProcRes);
} else {
for missing_patterns.each |pattern| {
for missing_patterns.iter().advance |pattern| {
error(fmt!("error pattern '%s' not found!", *pattern));
}
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],
testfile: &Path,
ProcRes: ProcRes) {
ProcRes: &ProcRes) {
// true if we found the error in question
let mut found_flags = vec::from_elem(
vec::len(expected_errors), false);
expected_errors.len(), false);
if ProcRes.status == 0 {
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)
});
}).collect::<~[~str]>();
// Scan and extract our error/warning messages,
// which look like:
@ -347,15 +355,15 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
// filename:line1:col1: line2:col2: *warning:* msg
// where line1:col1: is the starting point, line2:col2:
// 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;
for vec::eachi(expected_errors) |i, ee| {
for expected_errors.iter().enumerate().advance |(i, ee)| {
if !found_flags[i] {
debug!("prefix=%s ee.kind=%s ee.msg=%s line=%s",
prefixes[i], ee.kind, ee.msg, line);
if (str::starts_with(line, prefixes[i]) &&
str::contains(line, ee.kind) &&
str::contains(line, ee.msg)) {
if (line.starts_with(prefixes[i]) &&
line.contains(ee.kind) &&
line.contains(ee.msg)) {
found_flags[i] = true;
was_expected = true;
break;
@ -364,27 +372,27 @@ fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
}
// 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;
}
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'",
line),
ProcRes);
}
}
for uint::range(0u, vec::len(found_flags)) |i| {
for uint::range(0u, found_flags.len()) |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",
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;
return
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_integer(line, &mut i) &&
scan_char(line, ' ', &mut i) &&
(scan_string(line, ~"error", &mut i) ||
scan_string(line, ~"warning", &mut i));
(scan_string(line, "error", &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() {
return false;
}
let opt = str::find_char_from(haystack, needle, *idx);
let opt = haystack.slice_from(*idx).find(needle);
if opt.is_none() {
return false;
}
@ -414,11 +422,11 @@ fn scan_until_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
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() {
return false;
}
let range = str::char_range_at(haystack, *idx);
let range = haystack.char_range_at(*idx);
if range.ch != needle {
return false;
}
@ -426,10 +434,10 @@ fn scan_char(haystack: ~str, needle: char, idx: &mut uint) -> bool {
return true;
}
fn scan_integer(haystack: ~str, idx: &mut uint) -> bool {
fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
let mut i = *idx;
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 {
break;
}
@ -442,14 +450,14 @@ fn scan_integer(haystack: ~str, idx: &mut uint) -> bool {
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 needle_i = 0u;
while needle_i < needle.len() {
if haystack_i >= haystack.len() {
return false;
}
let range = str::char_range_at(haystack, haystack_i);
let range = haystack.char_range_at(haystack_i);
haystack_i = range.next;
if !scan_char(needle, range.ch, &mut needle_i) {
return false;
@ -463,44 +471,52 @@ struct ProcArgs {prog: ~str, args: ~[~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 {
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"])
}
fn compile_test_(config: config, props: TestProps,
fn compile_test_(config: &config, props: &TestProps,
testfile: &Path, extra_args: &[~str]) -> ProcRes {
let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
compose_and_run_compiler(
config, props, testfile,
make_compile_args(config, props, link_args + extra_args,
make_exe_name, testfile),
None)
let args = make_compile_args(config, props, link_args + extra_args,
make_exe_name, testfile);
compose_and_run_compiler(config, props, testfile, args, None)
}
fn exec_compiled_test(config: config, props: TestProps,
fn exec_compiled_test(config: &config, props: &TestProps,
testfile: &Path) -> ProcRes {
// If testing the new runtime then set the RUST_NEWRT env var
let env = if config.newrt {
props.exec_env + ~[(~"RUST_NEWRT", ~"1")]
} else {
props.exec_env
};
let env = copy props.exec_env;
let env = if config.newrt { env + &[(~"RUST_NEWRT", ~"1")] } else { env };
compose_and_run(config, testfile,
make_run_args(config, props, testfile),
env,
config.run_lib_path, None)
match config.target {
~"arm-linux-androideabi" => {
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(
config: config,
props: TestProps,
config: &config,
props: &TestProps,
testfile: &Path,
args: ProcArgs,
input: Option<~str>) -> ProcRes {
@ -512,7 +528,7 @@ fn compose_and_run_compiler(
let extra_link_args = ~[~"-L",
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 aux_args =
make_compile_args(config, props, ~[~"--lib"] + extra_link_args,
@ -523,7 +539,18 @@ fn compose_and_run_compiler(
fatal_ProcRes(
fmt!("auxiliary build of %s failed to compile: ",
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) {
if os::path_is_dir(path) { return; }
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,
ProcArgs: ProcArgs,
fn compose_and_run(config: &config, testfile: &Path,
ProcArgs{ args, prog }: ProcArgs,
procenv: ~[(~str, ~str)],
lib_path: ~str,
lib_path: &str,
input: Option<~str>) -> ProcRes {
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],
xform: &fn(config, (&Path)) -> Path,
fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str],
xform: &fn(&config, (&Path)) -> Path,
testfile: &Path) -> ProcArgs {
let prog = config.rustc_path;
let mut args = ~[testfile.to_str(),
~"-o", xform(config, testfile).to_str(),
~"-L", config.build_base.to_str()]
+ extras;
args += split_maybe_args(config.rustcflags);
args += split_maybe_args(props.compile_flags);
return ProcArgs {prog: prog.to_str(), args: args};
args.push_all_move(split_maybe_args(&config.rustcflags));
args.push_all_move(split_maybe_args(&props.compile_flags));
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
// happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile);
aux_output_dir_name(config, testfile).push_rel(&auxname)
}
fn make_exe_name(config: config, testfile: &Path) -> Path {
Path(output_base_name(config, testfile).to_str() +
str::from_slice(os::EXE_SUFFIX))
fn make_exe_name(config: &config, testfile: &Path) -> Path {
Path(output_base_name(config, testfile).to_str() + os::EXE_SUFFIX)
}
fn make_run_args(config: config, _props: TestProps, testfile: &Path) ->
fn make_run_args(config: &config, _props: &TestProps, testfile: &Path) ->
ProcArgs {
let toolargs = {
// If we've got another tool to run under (valgrind),
// then split apart its command
let runtool =
match config.runtool {
Some(s) => Some(s),
None => None
};
split_maybe_args(runtool)
};
// If we've got another tool to run under (valgrind),
// then split apart its command
let toolargs = split_maybe_args(&config.runtool);
let args = toolargs + ~[make_exe_name(config, testfile).to_str()];
return ProcArgs {prog: args[0],
args: vec::slice(args, 1, args.len()).to_vec()};
let mut args = toolargs + [make_exe_name(config, testfile).to_str()];
let prog = args.shift();
return ProcArgs {prog: prog, args: args};
}
fn split_maybe_args(argstr: Option<~str>) -> ~[~str] {
fn rm_whitespace(v: ~[~str]) -> ~[~str] {
v.filtered(|s| !str::is_whitespace(*s))
}
match argstr {
Some(s) => {
let mut ss = ~[];
for str::each_split_char(s, ' ') |s| { ss.push(s.to_owned()) }
rm_whitespace(ss)
fn split_maybe_args(argstr: &Option<~str>) -> ~[~str] {
match *argstr {
Some(ref s) => {
s.split_iter(' ')
.filter_map(|s| if s.is_whitespace() {None} else {Some(s.to_owned())})
.collect()
}
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)],
input: Option<~str>) -> ProcRes {
let cmdline =
@ -614,11 +628,12 @@ fn program_output(config: config, testfile: &Path, lib_path: ~str, prog: ~str,
logv(config, fmt!("executing %s", cmdline));
cmdline
};
let res = procsrv::run(lib_path, prog, args, env, input);
dump_output(config, testfile, res.out, res.err);
return ProcRes {status: res.status,
stdout: res.out,
stderr: res.err,
let procsrv::Result{ out, err, status } =
procsrv::run(lib_path, prog, args, env, input);
dump_output(config, testfile, out, err);
return ProcRes {status: status,
stdout: out,
stderr: err,
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 = "macos")]
#[cfg(target_os = "freebsd")]
fn make_cmdline(_libpath: ~str, prog: ~str, args: ~[~str]) -> ~str {
fmt!("%s %s", prog, str::connect(args, ~" "))
fn make_cmdline(_libpath: &str, prog: &str, args: &[~str]) -> ~str {
fmt!("%s %s", prog, args.connect(" "))
}
#[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,
str::connect(args, ~" "))
args.connect(" "))
}
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// 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))
}
fn dump_output(config: config, testfile: &Path, out: ~str, err: ~str) {
dump_output_file(config, testfile, out, ~"out");
dump_output_file(config, testfile, err, ~"err");
fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) {
dump_output_file(config, testfile, out, "out");
dump_output_file(config, testfile, err, "err");
maybe_dump_to_stdout(config, out, err);
}
fn dump_output_file(config: config, testfile: &Path,
out: ~str, extension: ~str) {
fn dump_output_file(config: &config, testfile: &Path,
out: &str, extension: &str) {
let outfile = make_out_name(config, testfile, extension);
let writer =
io::file_writer(&outfile, ~[io::Create, io::Truncate]).get();
io::file_writer(&outfile, [io::Create, io::Truncate]).get();
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)
}
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")
}
@ -668,16 +683,16 @@ fn output_testname(testfile: &Path) -> Path {
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
.push_rel(&output_testname(testfile))
.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 {
let sep1 = fmt!("------%s------------------------------", ~"stdout");
let sep2 = fmt!("------%s------------------------------", ~"stderr");
let sep1 = fmt!("------%s------------------------------", "stdout");
let sep2 = fmt!("------%s------------------------------", "stderr");
let sep3 = ~"------------------------------------------";
io::stdout().write_line(sep1);
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_ProcRes(err: ~str, ProcRes: ProcRes) -> ! {
fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! {
let msg =
fmt!("\n\
error: %s\n\
@ -709,3 +724,117 @@ stderr:\n\
io::stdout().write_str(msg);
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));
}
}
}
}

View File

@ -15,7 +15,7 @@ use common::config;
use core::io;
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
// maintain the current value while adding our own
@ -23,7 +23,7 @@ pub fn make_new_path(path: ~str) -> ~str {
Some(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")]
pub fn path_div() -> ~str { ~";" }
pub fn logv(config: config, s: ~str) {
pub fn logv(config: &config, s: ~str) {
debug!("%s", s);
if config.verbose { io::println(s); }
}

View File

@ -9,24 +9,23 @@
// except according to those terms.
#[no_core];
extern mod core(vers = "0.6");
#[no_std];
extern mod core(name = "std", vers = "0.7");
#[cfg(rustpkg)]
extern mod this(name = "rustpkg", vers = "0.6");
#[cfg(fuzzer)]
extern mod this(name = "fuzzer", vers = "0.6");
extern mod this(name = "rustpkg");
#[cfg(rustdoc)]
extern mod this(name = "rustdoc", vers = "0.6");
extern mod this(name = "rustdoc");
#[cfg(rusti)]
extern mod this(name = "rusti", vers = "0.6");
extern mod this(name = "rusti");
#[cfg(rust)]
extern mod this(name = "rust", vers = "0.6");
extern mod this(name = "rust");
#[cfg(rustc)]
extern mod this(name = "rustc", vers = "0.6");
extern mod this(name = "rustc");
fn main() { this::main() }

36
src/etc/adb_run_wrapper.sh Executable file
View 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

View File

@ -9,7 +9,7 @@ my $anchors = {};
my $i = 0;
foreach $line (@lines) {
$i++;
if ($line =~ m/id="([^"]+)"/) {
if ($line =~ m/id="([^"]+)"/) {
$anchors->{$1} = $i;
}
}
@ -17,10 +17,9 @@ foreach $line (@lines) {
$i = 0;
foreach $line (@lines) {
$i++;
while ($line =~ m/href="#([^"]+)"/g) {
while ($line =~ m/href="#([^"]+)"/g) {
if (! exists($anchors->{$1})) {
print "$file:$i: $1 referenced\n";
}
}
}

View File

@ -49,17 +49,18 @@ c.close()
d = open("tmp/run_pass_stage2_driver.rs", "w")
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("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(" let out = io::stdout();\n");
i = 0
for t in stage2_tests:
p = os.path.join("test", "run-pass", t)
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)
i += 1
d.write("}\n")

View File

@ -4,9 +4,8 @@
--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]*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]*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]*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/

View File

@ -23,7 +23,12 @@
:require '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)))
(c-populate-syntax-table table)
table))

View File

@ -57,10 +57,9 @@ while cur < len(lines):
if not ignore:
if not re.search(r"\bfn main\b", block):
block = "fn main() {\n" + block + "\n}\n"
if not re.search(r"\bextern mod std\b", block):
block = "extern mod std;\n" + block
if not re.search(r"\bextern mod extra\b", block):
block = "extern mod extra;\n" + block
block = """#[ forbid(ctypes) ];
#[ forbid(deprecated_mode) ];
#[ forbid(deprecated_pattern) ];
#[ forbid(implicit_copies) ];
#[ forbid(non_implicitly_copyable_typarams) ];
@ -68,12 +67,9 @@ while cur < len(lines):
#[ forbid(type_limits) ];
#[ forbid(unrecognized_lint) ];
#[ forbid(unused_imports) ];
#[ forbid(vecs_implicitly_copyable) ];
#[ forbid(while_true) ];
#[ warn(deprecated_self) ];
#[ warn(non_camel_case_types) ];
#[ warn(structural_records) ];\n
#[ warn(non_camel_case_types) ];\n
""" + block
if xfail:
block = "// xfail-test\n" + block

View File

@ -8,4 +8,3 @@ Instructions for Ubuntu Linux 12.04+
2) Copy the included "share" folder into "~/.local/"
3) Open a shell in "~/.local/share/" and run "update-mime-database mime"

View File

@ -123,11 +123,11 @@
<keyword>mode_t</keyword>
<keyword>ssize_t</keyword>
</context>
<context id="self" style-ref="identifier">
<keyword>self</keyword>
</context>
<context id="constants" style-ref="constant">
<keyword>true</keyword>
<keyword>false</keyword>
@ -261,4 +261,3 @@
</definitions>
</language>

View File

@ -2,6 +2,6 @@
<mime-type type="text/x-rust">
<comment>Rust Source</comment>
<glob pattern="*.rs"/>
<glob pattern="*.rc"/>
<glob pattern="*.rc"/>
</mime-type>
</mime-info>

View File

@ -14,4 +14,3 @@ while (<>) {
$indent -= 1;
}
}

View File

@ -7,7 +7,7 @@
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
<!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>
<list name="fn">
<item> fn </item>
@ -49,6 +49,7 @@
<item> Copy </item>
<item> Send </item>
<item> Owned </item>
<item> Sized </item>
<item> Eq </item>
<item> Ord </item>
<item> Num </item>
@ -57,8 +58,8 @@
<item> Add </item>
<item> Sub </item>
<item> Mul </item>
<item> Div </item>
<item> Modulo </item>
<item> Quot </item>
<item> Rem </item>
<item> Neg </item>
<item> BitAnd </item>
<item> BitOr </item>

View File

@ -52,5 +52,3 @@ def download_new_file (date, rev, platform, hsh):
for ff in newestSet["files"]:
download_new_file (newestSet["date"], newestSet["rev"],
ff["platform"], ff["hash"])

View File

@ -243,4 +243,3 @@ int main() {
extra_consts();
printf("}\n");
}

View File

@ -96,4 +96,3 @@ def check_license(name, contents):
return True
return False

Binary file not shown.

View File

@ -1,13 +1,13 @@
#!/bin/sh
TARG_DIR=$1
TARG_DIR=$1
PREFIX=$2
BINDIR=bin
LIBDIR=lib
OS=`uname -s`
case $OS in
case $OS in
("Linux"|"FreeBSD")
BIN_SUF=
LIB_SUF=.so

View File

@ -33,6 +33,3 @@ for line in f.readlines():
print("got download with ok hash")
else:
raise Exception("bad hash on download")

View File

@ -77,4 +77,3 @@ while (my ($key, $substs) = each %funcs) {
}
print "\n";
}

View File

@ -1,4 +1,5 @@
#define CFG_VERSION GetEnv("CFG_VERSION")
#define CFG_VERSION_WIN GetEnv("CFG_VERSION_WIN")
[Setup]
@ -8,7 +9,7 @@ AppVersion={#CFG_VERSION}
AppCopyright=Copyright (C) 2006-2013 Mozilla Foundation, MIT license
AppPublisher=Mozilla Foundation
AppPublisherURL=http://www.rust-lang.org
VersionInfoVersion={#CFG_VERSION}
VersionInfoVersion={#CFG_VERSION_WIN}
LicenseFile=LICENSE.txt
DisableWelcomePage=true

View File

@ -26,29 +26,29 @@ download_unpack_base = os.path.join(download_dir_base, "unpack")
snapshot_files = {
"linux": ["bin/rustc",
"lib/libcore-*.so",
"lib/libstd-*.so",
"lib/libextra-*.so",
"lib/librustc-*.so",
"lib/libsyntax-*.so",
"lib/librustrt.so",
"lib/librustllvm.so"],
"macos": ["bin/rustc",
"lib/libcore-*.dylib",
"lib/libstd-*.dylib",
"lib/libextra-*.dylib",
"lib/librustc-*.dylib",
"lib/libsyntax-*.dylib",
"lib/librustrt.dylib",
"lib/librustllvm.dylib"],
"winnt": ["bin/rustc.exe",
"bin/core-*.dll",
"bin/std-*.dll",
"bin/extra-*.dll",
"bin/rustc-*.dll",
"bin/syntax-*.dll",
"bin/rustrt.dll",
"bin/rustllvm.dll"],
"freebsd": ["bin/rustc",
"lib/libcore-*.so",
"lib/libstd-*.so",
"lib/libextra-*.so",
"lib/librustc-*.so",
"lib/libsyntax-*.so",
"lib/librustrt.so",

Binary file not shown.

View File

@ -80,4 +80,3 @@ def sugarise_file(path):
for (dirpath, dirnames, filenames) in os.walk('.'):
for name in fnmatch.filter(filenames, '*.r[sc]'):
sugarise_file(os.path.join(dirpath, name))

View File

@ -81,4 +81,3 @@ except UnicodeDecodeError, e:
sys.exit(err)

View File

@ -112,12 +112,54 @@ def escape_char(c):
return "'\\u%4.4x'" % 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):
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)
keys = tbl.keys()
keys.sort()
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")
prefix = ' '
for pair in tbl[cat]:
@ -193,8 +235,27 @@ for i in [r]:
rf = open(r, "w")
(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_decomp_module(rf, canon_decomp, compat_decomp)
derived = load_derived_core_properties("DerivedCoreProperties.txt")
emit_property_module(rf, "derived_property", derived)

View File

@ -1,5 +0,0 @@
"Highlight the 100th text column
"Feature became available in v7.3
if version >= 703
set colorcolumn=100
endif

View File

@ -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
endif
@ -11,10 +11,6 @@ syn match rustRightArrowHead contained ">" conceal cchar= 
syn match rustRightArrowTail contained "-" conceal cchar=
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 rustFatRightArrowTail contained "=" conceal cchar=
syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail

View File

@ -5,4 +5,7 @@ if exists("b:did_indent")
endif
let b:did_indent = 1
setlocal smartindent
setlocal cindent
setlocal cinoptions=L0,(0,Ws,JN
setlocal cinkeys=0{,0},!^F,o,O

View File

@ -2,7 +2,7 @@
" Language: Rust
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Last Change: 2012 Dec 25
" Last Change: 2013 Jun 14
if version < 600
syntax clear
@ -13,13 +13,16 @@ endif
syn keyword rustConditional match if else
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 copy do drop extern
syn keyword rustKeyword copy do extern
syn keyword rustKeyword for impl let log
syn keyword rustKeyword loop mod once priv pub
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
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier 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 rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
" Reserved words
syn keyword rustKeyword m32 m64 m128 f80 f16 f128 be
" reserved
syn keyword rustKeyword be
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
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 off_t dev_t ino_t pid_t mode_t ssize_t
syn keyword rustTrait Const Copy Send Owned " inherent traits
syn keyword rustTrait Eq Ord Num Ptr
syn keyword rustTrait Drop Add Sub Mul Div Modulo Neg BitAnd BitOr
syn keyword rustTrait Const Copy Send Owned Sized " inherent traits
syn keyword rustTrait Clone Decodable Encodable IterBytes Rand ToStr
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 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 (first "\w" to "\u").
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 rustFuncCall "\w\(\w\)*("he=e-1,me=e-1
syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::<T>();
syn match rustMacro '\w\(\w\)*!'
syn match rustMacro '#\w\(\w\)*'
syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail
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 "%%" contained
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
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 rustCharacter "'\([^'\\]\|\\\(['nrt\\\"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'"
syn region rustComment start="/\*" end="\*/" contains=rustComment,rustTodo
syn region rustComment start="//" skip="\\$" end="$" contains=rustTodo keepend
syn region rustCommentDoc start="/\*[\*!]" end="\*/"
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
@ -134,16 +143,24 @@ hi def link rustConditional Conditional
hi def link rustIdentifier Identifier
hi def link rustModPath Include
hi def link rustFuncName Function
hi def link rustFuncCall Function
hi def link rustCommentDoc SpecialComment
hi def link rustComment Comment
hi def link rustMacro Macro
hi def link rustType Type
hi def link rustTodo Todo
hi def link rustAttribute PreProc
hi def link rustDeriving PreProc
hi def link rustStorage StorageClass
hi def link rustLifetime Special
" Other Suggestions:
" hi rustAttribute ctermfg=cyan
" hi rustDeriving ctermfg=cyan
" hi rustAssert ctermfg=yellow
" hi rustFail ctermfg=red
" hi rustMacro ctermfg=magenta
" hi rustModPathSep ctermfg=grey
syn sync minlines=200
syn sync maxlines=500

View File

@ -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
Memcheck:Leak
fun:_Znwj
@ -471,7 +401,7 @@
Helgrind:Race
fun:_ZN15lock_and_signal27lock_held_by_current_threadEv
...
}
}
{
lock_and_signal-probably-threadsafe-access-outside-of-lock2
@ -565,3 +495,10 @@
fun:__gxx_personality_v0
...
}
{
goddammit-llvm-why-u-no-valgrind
Memcheck:Cond
fun:*
...
}

121
src/etc/ziggurat_tables.py Executable file
View 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
View 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"'

View File

@ -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]]);
}

View File

@ -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:

View File

@ -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"));
}
}
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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:
//

View File

@ -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));
}
}

View File

@ -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>;
}

View File

@ -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);
}
}
}
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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); }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}

View File

@ -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)));
}

View File

@ -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| {
}
}
}
}

View File

@ -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:
//

View File

@ -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:
//

View File

@ -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:
//

View File

@ -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| {}
}

View File

@ -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)));
}

View File

@ -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