mirror of
https://git.proxmox.com/git/rustc
synced 2025-05-02 13:35:17 +00:00
Imported Upstream version 0.7
This commit is contained in:
parent
223e47cc31
commit
970d7e83e1
228
AUTHORS.txt
Normal file
228
AUTHORS.txt
Normal file
@ -0,0 +1,228 @@
|
||||
Initial author, project lead, target of blame:
|
||||
|
||||
Graydon Hoare <graydon@mozilla.com>
|
||||
|
||||
Other authors:
|
||||
|
||||
|
||||
Adam Bozanich <adam.boz@gmail.com>
|
||||
Aleksander Balicki <balicki.aleksander@gmail.com>
|
||||
Alex Crichton <alex@alexcrichton.com>
|
||||
Alex Rønne Petersen <alex@lycus.org>
|
||||
Alexander Stavonin <a.stavonin@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Andreas Gal <gal@mozilla.com>
|
||||
Andrew Dunham <andrew@du.nham.ca>
|
||||
Andrew Paseltiner <apaseltiner@gmail.com>
|
||||
Anthony Juckel <ajuckel@gmail.com>
|
||||
Arkaitz Jimenez <arkaitzj@gmail.com>
|
||||
Armin Ronacher <armin.ronacher@active-4.com>
|
||||
Ashok Gautham <ScriptDevil@gmail.com>
|
||||
Austin Seipp <mad.one@gmail.com>
|
||||
Aydin Kim <ladinjin@hanmail.net>
|
||||
auREAX <mark@xn--hwg34fba.ws>
|
||||
Ben Alpert <ben@benalpert.com>
|
||||
Ben Blum <bblum@andrew.cmu.edu>
|
||||
Ben Kelly <ben@wanderview.com>
|
||||
Ben Striegel <ben.striegel@gmail.com>
|
||||
Benjamin Herr <ben@0x539.de>
|
||||
Benjamin Jackman <ben@jackman.biz>
|
||||
Benjamin Kircher <benjamin.kircher@gmail.com>
|
||||
Benjamin Peterson <benjamin@python.org>
|
||||
Bilal Husain <bilal@bilalhusain.com>
|
||||
Bill Fallon <bill.fallon@robos.li>
|
||||
Bill Myers <bill_myers@outlook.com>
|
||||
Bill Wendling <wendling@apple.com>
|
||||
Björn Steinbrink <bsteinbr@gmail.com>
|
||||
Brendan Eich <brendan@mozilla.org>
|
||||
Brendan Zabarauskas <bjzaba@yahoo.com.au>
|
||||
Brett Cannon <brett@python.org>
|
||||
Brian Anderson <banderson@mozilla.com>
|
||||
Brian J. Burg <burg@cs.washington.edu>
|
||||
Brian Leibig <brian.leibig@gmail.com>
|
||||
Bryan Dunsmore <dunsmoreb@gmail.com>
|
||||
Caitlin Potter <snowball@defpixel.com>
|
||||
Chris Double <chris.double@double.co.nz>
|
||||
Chris Peterson <cpeterson@mozilla.com>
|
||||
Chris Pressey <cpressey@gmail.com>
|
||||
Cody Schroeder <codys@cs.washington.edu>
|
||||
Corey Richardson <corey@octayn.net>
|
||||
Damian Gryski <damian@gryski.com>
|
||||
Damien Grassart <damien@grassart.com>
|
||||
Damien Schoof <damien.schoof@gmail.com>
|
||||
Daniel Brooks <db48x@db48x.net>
|
||||
Daniel Farina <daniel@fdr.io>
|
||||
Dan Luu <danluu@gmail.com>
|
||||
Daniel Luz <dev@mernen.com>
|
||||
Daniel Micay <danielmicay@gmail.com>
|
||||
Daniel Patterson <dbp@riseup.net>
|
||||
Daniel Ralston <Wubbulous@gmail.com>
|
||||
Daniel Ursache Dogariu <contact@danniel.net>
|
||||
Dave Herman <dherman@mozilla.com>
|
||||
David Forsythe <dforsythe@gmail.com>
|
||||
David Klein <david.klein@baesystemsdetica.com>
|
||||
David Rajchenbach-Teller <dteller@mozilla.com>
|
||||
Diggory Hardy <diggory.hardy@gmail.com>
|
||||
Dimitri Krassovski <labria@startika.com>
|
||||
Donovan Preston <donovanpreston@gmail.com>
|
||||
Drew Willcoxon <adw@mozilla.com>
|
||||
Elliott Slaughter <elliottslaughter@gmail.com>
|
||||
Elly Fong-Jones <elly@leptoquark.net>
|
||||
Eric Holk <eric.holk@gmail.com>
|
||||
Eric Holmes <eric@ejholmes.net>
|
||||
Erick Tryzelaar <erick.tryzelaar@gmail.com>
|
||||
Erik Rose <erik@mozilla.com>
|
||||
Evan McClanahan <evan@evanmcc.com>
|
||||
Fedor Indutny <fedor.indutny@gmail.com>
|
||||
Felix S. Klock II <pnkfelix@pnkfx.org>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Franklin Chen <franklinchen@franklinchen.com>
|
||||
Gábor Horváth <xazax.hun@gmail.com>
|
||||
Gabriel <g2p.code@gmail.com>
|
||||
Gareth Daniel Smith <garethdanielsmith@gmail.com>
|
||||
gifnksm <makoto.nksm@gmail.com>
|
||||
Glenn Willen <gwillen@nerdnet.org>
|
||||
Gonçalo Cabrita <_@gmcabrita.com>
|
||||
Graham Fawcett <fawcett@uwindsor.ca>
|
||||
Grahame Bowland <grahame@angrygoats.net>
|
||||
Haitao Li <lihaitao@gmail.com>
|
||||
hansjorg <hansjorg@gmail.com>
|
||||
Herman J. Radtke III <hermanradtke@gmail.com>
|
||||
Huon Wilson <dbau.pp+github@gmail.com>
|
||||
Ian D. Bollinger <ian.bollinger@gmail.com>
|
||||
Ilyong Cho <ilyoan@gmail.com>
|
||||
Isaac Aggrey <isaac.aggrey@gmail.com>
|
||||
Ivano Coppola <rgbfirefox@gmail.com>
|
||||
Jack Moffitt <jack@metajack.im>
|
||||
Jacob Harris Cryer Kragh <jhckragh@gmail.com>
|
||||
Jacob Parker <j3parker@csclub.uwaterloo.ca>
|
||||
Jakub Wieczorek <jakubw@jakubw.net>
|
||||
James Miller <bladeon@gmail.com>
|
||||
James Tranovich <james@openhorizonlabs.com>
|
||||
Jason Orendorff <jorendorff@mozilla.com>
|
||||
Jed Davis <jld@panix.com>
|
||||
Jeff Balogh <jbalogh@mozilla.com>
|
||||
Jeff Muizelaar <jmuizelaar@mozilla.com>
|
||||
Jeff Olson <olson.jeffery@gmail.com>
|
||||
Jeffrey Yasskin <jyasskin@gmail.com>
|
||||
Jeong YunWon <jeong@youknowone.org>
|
||||
Jens Nockert <jens@nockert.se>
|
||||
Jesse Jones <jesse9jones@gmail.com>
|
||||
Jesse Luehrs <doy@tozt.net>
|
||||
Jesse Ruderman <jruderman@gmail.com>
|
||||
Jihyun Yu <jihyun@nclab.kaist.ac.kr>
|
||||
Jim Blandy <jimb@red-bean.com>
|
||||
Jimmy Lu <jimmy.lu.2011@gmail.com>
|
||||
J. J. Weber <jjweber@gmail.com>
|
||||
Joe Pletcher <joepletcher@gmail.com>
|
||||
John Clements <clements@racket-lang.org>
|
||||
Jon Morton <jonanin@gmail.com>
|
||||
Jonathan Sternberg <jonathansternberg@gmail.com>
|
||||
Josh Matthews <josh@joshmatthews.net>
|
||||
Joshua Clark <joshua.clark@txstate.edu>
|
||||
Joshua Wise <joshua@joshuawise.com>
|
||||
Junyoung Cho <june0.cho@samsung.com>
|
||||
Jyun-Yan You <jyyou@cs.nctu.edu.tw>
|
||||
Kang Seonghoon <kang.seonghoon@mearie.org>
|
||||
Kelly Wilson <wilsonk@cpsc.ucalgary.ca>
|
||||
Kevin Atkinson <kevina@cs.utah.edu>
|
||||
Kevin Ballard <kevin@sb.org>
|
||||
Kevin Cantu <me@kevincantu.org>
|
||||
klutzy <klutzytheklutzy@gmail.com>
|
||||
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
|
||||
Laurent Bonnans <bonnans.l@gmail.com>
|
||||
Lawrence Velázquez <larryv@alum.mit.edu>
|
||||
Leah Hanson <astrieanna@gmail.com>
|
||||
Lennart Kudling <github@kudling.de>
|
||||
Lindsey Kuper <lindsey@composition.al>
|
||||
Luca Bruno <lucab@debian.org>
|
||||
Luqman Aden <laden@csclub.uwaterloo.ca>
|
||||
Magnus Auvinen <magnus.auvinen@gmail.com>
|
||||
Mahmut Bulut <mahmutbulut0@gmail.com>
|
||||
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
|
||||
Marijn Haverbeke <marijnh@gmail.com>
|
||||
Mark Lacey <641@rudkx.com>
|
||||
Mark Vian <mrv.caseus@gmail.com>
|
||||
Marti Raudsepp <marti@juffo.org>
|
||||
Martin DeMello <martindemello@gmail.com>
|
||||
Marvin Löbel <loebel.marvin@gmail.com>
|
||||
Matt Brubeck <mbrubeck@limpet.net>
|
||||
Matthew McPherrin <matthew@mcpherrin.ca>
|
||||
Matthew O'Connor <thegreendragon@gmail.com>
|
||||
Matthijs Hofstra <thiezz@gmail.com>
|
||||
Max Penet <max.penet@gmail.com>
|
||||
Michael Arntzenius <daekharel@gmail.com>
|
||||
Michael Bebenita <mbebenita@mozilla.com>
|
||||
Michael Neumann <mneumann@ntecs.de>
|
||||
Michael Sullivan <sully@msully.net>
|
||||
Mikko Perttunen <cyndis@kapsi.fi>
|
||||
Nick Desaulniers <ndesaulniers@mozilla.com>
|
||||
Niko Matsakis <niko@alum.mit.edu>
|
||||
Olivier Saut <osaut@airpost.net>
|
||||
Or Brostovski <tohava@gmail.com>
|
||||
Orphée Lafond-Lummis <o@orftz.com>
|
||||
Patrick Walton <pwalton@mozilla.com>
|
||||
Patrik Kårlin <patrik.karlin@gmail.com>
|
||||
Paul Stansifer <paul.stansifer@gmail.com>
|
||||
Paul Woolcock <pwoolcoc+github@gmail.com>
|
||||
Pavel Panchekha <me@pavpanchekha.com>
|
||||
Peter Hull <peterhull90@gmail.com>
|
||||
Peter Williams <peter@newton.cx>
|
||||
Philipp Brüschweiler <blei42@gmail.com>
|
||||
Rafael Ávila de Espíndola <respindola@mozilla.com>
|
||||
Ralph Bodenner <rkbodenner+github@gmail.com>
|
||||
Ralph Giles <giles@thaumas.net>
|
||||
Ramkumar Ramachandra <artagnon@gmail.com>
|
||||
Reuben Morais <reuben.morais@gmail.com>
|
||||
Rick Waldron <waldron.rick@gmail.com>
|
||||
Rob Arnold <robarnold@cs.cmu.edu>
|
||||
Rob Hoelz <rob@hoelz.ro>
|
||||
Roland Tanglao <roland@rolandtanglao.com>
|
||||
Ron Dahlgren <ronald.dahlgren@gmail.com>
|
||||
Roy Frostig <rfrostig@mozilla.com>
|
||||
Ryan Scheel <ryan.havvy@gmail.com>
|
||||
Samuel Chase <samebchase@gmail.com>
|
||||
Sander Mathijs van Veen <smvv@kompiler.org>
|
||||
Sangeun Kim <sammy.kim@samsung.com>
|
||||
Saurabh Anand <saurabhanandiit@gmail.com>
|
||||
Sean Moon <ssamoon@ucla.edu>
|
||||
Sean Stangl <sstangl@mozilla.com>
|
||||
Sebastian N. Fernandez <cachobot@gmail.com>
|
||||
Seth Pink <sethpink@gmail.com>
|
||||
Seo Sanghyeon <sanxiyn@gmail.com>
|
||||
sevrak <sevrak@rediffmail.com>
|
||||
SiegeLord <slabode@aim.com>
|
||||
Simon Barber-Dueck <sbarberdueck@gmail.com>
|
||||
Simon Sapin <simon@exyr.org>
|
||||
startling <tdixon51793@gmail.com>
|
||||
Stefan Plantikow <stefan.plantikow@googlemail.com>
|
||||
Steve Klabnik <steve@steveklabnik.com>
|
||||
Steven De Coeyer <steven@banteng.be>
|
||||
Steven Fackler <sfackler@gmail.com>
|
||||
Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca>
|
||||
Taras Shpot <mrshpot@gmail.com>
|
||||
Ted Horst <ted.horst@earthlink.net>
|
||||
Thad Guidry <thadguidry@gmail.com>
|
||||
Thomas Daede <daede003@umn.edu>
|
||||
Tim Chevalier <chevalier@alum.wellesley.edu>
|
||||
Tim Taubert <tim@timtaubert.de>
|
||||
Tom Lee <github@tomlee.co>
|
||||
Tommy M. McGuire <mcguire@crsr.net>
|
||||
Tomoki Aonuma <uasi@99cm.org>
|
||||
Tony Young <tony@rfw.name>
|
||||
Trinick <slicksilver555@mac.com>
|
||||
Tycho Sci <tychosci@gmail.com>
|
||||
Tyler Bindon <martica@martica.org>
|
||||
Uwe Dauernheim <uwe@dauernheim.net>
|
||||
Vadim Chugunov <vadimcn@gmail.com>
|
||||
Viktor Dahl <pazaconyoman@gmail.com>
|
||||
Vincent Belliard <vincent@famillebelliard.fr>
|
||||
Vivek Galatage <vivekgalatage@gmail.com>
|
||||
Wade Mealing <wmealing@gmail.com>
|
||||
William Ting <william.h.ting@gmail.com>
|
||||
Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
|
||||
Young-il Choi <duddlf.choi@samsung.com>
|
||||
Youngmin Yoo <youngmin.yoo@samsung.com>
|
||||
Youngsoo Son <ysson83@gmail.com>
|
||||
Zack Corr <zack@z0w0.me>
|
||||
zofrex <zofrex@gmail.com>
|
@ -367,4 +367,3 @@ their own copyright notices and license terms:
|
||||
has chosen for the collective work, enumerated at the top
|
||||
of this file. The only difference is the retention of
|
||||
copyright itself, held by the contributor.
|
||||
|
||||
|
105
Makefile.in
105
Makefile.in
@ -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
|
||||
|
10
README.md
10
README.md
@ -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
98
configure
vendored
@ -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=
|
||||
|
29
doc/README
29
doc/README
@ -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
|
||||
|
97
doc/rust.css
97
doc/rust.css
@ -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;
|
||||
}
|
||||
|
365
doc/rust.md
365
doc/rust.md
@ -17,14 +17,14 @@ This document does not serve as a tutorial introduction to the
|
||||
language. Background familiarity with the language is assumed. A separate
|
||||
[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
137
doc/rustpkg.md
Normal file
@ -0,0 +1,137 @@
|
||||
% Rustpkg Reference Manual
|
||||
|
||||
# Introduction
|
||||
|
||||
This document is the reference manual for the Rustpkg packaging and build tool for the Rust programming language.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Rustpkg is a work in progress, as is this reference manual.
|
||||
If the actual behavior of rustpkg differs from the behavior described in this reference,
|
||||
that reflects either an incompleteness or a bug in rustpkg.
|
||||
|
||||
# Package searching
|
||||
|
||||
rustpkg searches for packages using the `RUST_PATH` environment variable,
|
||||
which is a colon-separated list (semicolon-separated on Windows) of directories.
|
||||
|
||||
Each directory in this list is a *workspace* for rustpkg.
|
||||
|
||||
`RUST_PATH` implicitly contains an entry for `./.rust` (as well as
|
||||
`../.rust`, `../../.rust`,
|
||||
and so on for every parent of `.` up to the filesystem root).
|
||||
That means that if `RUST_PATH` is not set,
|
||||
then rustpkg will still search for workspaces in `./.rust` and so on.
|
||||
`RUST_PATH` also implicitly contains an entry for the system path:
|
||||
`/usr/local` or the equivalent on Windows.
|
||||
This entry comes after the implicit entries for `./.rust` and so on.
|
||||
Finally, the last implicit entry in `RUST_PATH` is `~/.rust`
|
||||
or the equivalent on Windows.
|
||||
|
||||
Each workspace may contain one or more packages.
|
||||
|
||||
When building code that contains one or more directives of the form `extern mod P`,
|
||||
rustpkg automatically searches for packages named `P` in the `RUST_PATH` (as described above).
|
||||
It builds those dependencies if necessary.
|
||||
Thus, when using rustpkg,
|
||||
there is no need for `-L` flags to tell the linker where to find libraries for external crates.
|
||||
|
||||
# Package structure
|
||||
|
||||
A valid workspace must contain each of the following subdirectories:
|
||||
|
||||
* 'src/': contains one subdirectory per package. Each subdirectory contains source files for a given package.
|
||||
|
||||
For example, if `foo` is a workspace containing the package `bar`,
|
||||
then `foo/src/bar/main.rs` could be the `main` entry point for
|
||||
building a `bar` executable.
|
||||
* 'lib/': `rustpkg install` installs libraries into a target-specific subdirectory of this directory.
|
||||
|
||||
For example, on a 64-bit machine running Mac OS X,
|
||||
if `foo` is a workspace containing the package `bar`,
|
||||
rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
|
||||
The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
|
||||
where [hash] is a hash of the package ID.
|
||||
* 'bin/': `rustpkg install` installs executable binaries into a target-specific subdirectory of this directory.
|
||||
|
||||
For example, on a 64-bit machine running Mac OS X,
|
||||
if `foo` is a workspace, containing the package `bar`,
|
||||
rustpkg will install executables for `bar` to
|
||||
`foo/bin/x86_64-apple-darwin/`.
|
||||
The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`.
|
||||
* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
|
||||
|
||||
For example, on a 64-bit machine running Mac OS X,
|
||||
if `foo` is a workspace containing the package `bar` and `foo/src/bar/main.rs` exists,
|
||||
then `rustpkg build` will create `foo/build/x86_64-apple-darwin/bar/main.o`.
|
||||
|
||||
# Package identifiers
|
||||
|
||||
A package identifier identifies a package uniquely.
|
||||
A package can be stored in a workspace on the local file system,
|
||||
or on a remote Web server, in which case the package ID resembles a URL.
|
||||
For example, `github.com/mozilla/rust` is a package ID
|
||||
that would refer to the git repository browsable at `http://github.com/mozilla/rust`.
|
||||
A package ID can also specify a version, like:
|
||||
`github.com/mozilla/rust#0.3`.
|
||||
In this case, `rustpkg` will check that the repository `github.com/mozilla/rust` has a tag named `0.3`,
|
||||
and report an error otherwise.
|
||||
|
||||
## Source files
|
||||
|
||||
rustpkg searches for four different fixed filenames in order to determine the crates to build:
|
||||
|
||||
* `main.rs`: Assumed to be a main entry point for building an executable.
|
||||
* `lib.rs`: Assumed to be a library crate.
|
||||
* `test.rs`: Assumed to contain tests declared with the `#[test]` attribute.
|
||||
* `bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` attribute.
|
||||
|
||||
## Versions
|
||||
|
||||
`rustpkg` packages do not need to declare their versions with an attribute inside one of the source files,
|
||||
because `rustpkg` infers it from the version control system.
|
||||
When building a package that is in a `git` repository,
|
||||
`rustpkg` assumes that the most recent tag specifies the current version.
|
||||
When building a package that is not under version control,
|
||||
or that has no tags, `rustpkg` assumes the intended version is 0.1.
|
||||
|
||||
# Dependencies
|
||||
|
||||
rustpkg infers dependencies from `extern mod` directives.
|
||||
Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library.
|
||||
(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.)
|
||||
|
||||
# Custom build scripts
|
||||
|
||||
A file called `pkg.rs` at the root level in a workspace is called a *package script*.
|
||||
If a package script exists, rustpkg executes it to build the package
|
||||
rather than inferring crates as described previously.
|
||||
|
||||
Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build.
|
||||
`rustpkg::api` contains functions to build, install, or clean libraries and executables
|
||||
in the way rustpkg normally would without custom build logic.
|
||||
|
||||
# Command reference
|
||||
|
||||
## build
|
||||
|
||||
`rustpkg build foo` searches for a package with ID `foo`
|
||||
and builds it in any workspace(s) where it finds one.
|
||||
Supposing such packages are found in workspaces X, Y, and Z,
|
||||
the command leaves behind files in `X`'s, `Y`'s, and `Z`'s `build` directories,
|
||||
but not in their `lib` or `bin` directories.
|
||||
|
||||
## clean
|
||||
|
||||
`rustpkg clean foo` deletes the contents of `foo`'s `build` directory.
|
||||
|
||||
## install
|
||||
|
||||
`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`,
|
||||
and then installs them either into `foo`'s `lib` and `bin` directories,
|
||||
or into the `lib` and `bin` subdirectories of the first entry in `RUST_PATH`.
|
||||
|
||||
## test
|
||||
|
||||
`rustpkg test foo` builds `foo`'s `test.rs` file if necessary,
|
||||
then runs the resulting test executable.
|
@ -42,14 +42,14 @@ point, but allocated in a different place:
|
||||
~~~
|
||||
# struct Point {x: float, y: float}
|
||||
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
|
||||
|
||||
We’ve seen a few examples so far of borrowing heap boxes, both managed
|
||||
and unique. Up till this point, we’ve glossed over issues of
|
||||
and owned. Up till this point, we’ve glossed over issues of
|
||||
safety. As stated in the introduction, at runtime a borrowed pointer
|
||||
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 don’t 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
207
doc/tutorial-container.md
Normal file
@ -0,0 +1,207 @@
|
||||
% Containers and iterators
|
||||
|
||||
# Containers
|
||||
|
||||
The container traits are defined in the `std::container` module.
|
||||
|
||||
## Unique and managed vectors
|
||||
|
||||
Vectors have `O(1)` indexing and removal from the end, along with `O(1)`
|
||||
amortized insertion. Vectors are the most common container in Rust, and are
|
||||
flexible enough to fit many use cases.
|
||||
|
||||
Vectors can also be sorted and used as efficient lookup tables with the
|
||||
`std::vec::bsearch` function, if all the elements are inserted at one time and
|
||||
deletions are unnecessary.
|
||||
|
||||
## Maps and sets
|
||||
|
||||
Maps are collections of unique keys with corresponding values, and sets are
|
||||
just unique keys without a corresponding value. The `Map` and `Set` traits in
|
||||
`std::container` define the basic interface.
|
||||
|
||||
The standard library provides three owned map/set types:
|
||||
|
||||
* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to
|
||||
implement `Eq` and `Hash`
|
||||
* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint`
|
||||
* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys
|
||||
to implement `TotalOrd`
|
||||
|
||||
These maps do not use managed pointers so they can be sent between tasks as
|
||||
long as the key and value types are sendable. Neither the key or value type has
|
||||
to be copyable.
|
||||
|
||||
The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
|
||||
order.
|
||||
|
||||
Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
|
||||
making the order of a set of keys in a given hash table randomized. Rust
|
||||
provides a [SipHash](https://131002.net/siphash/) implementation for any type
|
||||
implementing the `IterBytes` trait.
|
||||
|
||||
## Double-ended queues
|
||||
|
||||
The `extra::deque` module implements a double-ended queue with `O(1)` amortized
|
||||
inserts and removals from both ends of the container. It also has `O(1)`
|
||||
indexing like a vector. The contained elements are not required to be copyable,
|
||||
and the queue will be sendable if the contained type is sendable.
|
||||
|
||||
## Priority queues
|
||||
|
||||
The `extra::priority_queue` module implements a queue ordered by a key. The
|
||||
contained elements are not required to be copyable, and the queue will be
|
||||
sendable if the contained type is sendable.
|
||||
|
||||
Insertions have `O(log n)` time complexity and checking or popping the largest
|
||||
element is `O(1)`. Converting a vector to a priority queue can be done
|
||||
in-place, and has `O(n)` complexity. A priority queue can also be converted to
|
||||
a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
|
||||
heapsort.
|
||||
|
||||
# Iterators
|
||||
|
||||
## Iteration protocol
|
||||
|
||||
The iteration protocol is defined by the `Iterator` trait in the
|
||||
`std::iterator` module. The minimal implementation of the trait is a `next`
|
||||
method, yielding the next element from an iterator object:
|
||||
|
||||
~~~
|
||||
/// An infinite stream of zeroes
|
||||
struct ZeroStream;
|
||||
|
||||
impl Iterator<int> for ZeroStream {
|
||||
fn next(&mut self) -> Option<int> {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
Reaching the end of the iterator is signalled by returning `None` instead of
|
||||
`Some(item)`:
|
||||
|
||||
~~~
|
||||
/// A stream of N zeroes
|
||||
struct ZeroStream {
|
||||
priv remaining: uint
|
||||
}
|
||||
|
||||
impl ZeroStream {
|
||||
fn new(n: uint) -> ZeroStream {
|
||||
ZeroStream { remaining: n }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator<int> for ZeroStream {
|
||||
fn next(&mut self) -> Option<int> {
|
||||
if self.remaining == 0 {
|
||||
None
|
||||
} else {
|
||||
self.remaining -= 1;
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
## Container iterators
|
||||
|
||||
Containers implement iteration over the contained elements by returning an
|
||||
iterator object. For example, vectors have four iterators available:
|
||||
|
||||
* `vector.iter()`, for immutable references to the elements
|
||||
* `vector.mut_iter()`, for mutable references to the elements
|
||||
* `vector.rev_iter()`, for immutable references to the elements in reverse order
|
||||
* `vector.mut_rev_iter()`, for mutable references to the elements in reverse order
|
||||
|
||||
### Freezing
|
||||
|
||||
Unlike most other languages with external iterators, Rust has no *iterator
|
||||
invalidation*. As long an iterator is still in scope, the compiler will prevent
|
||||
modification of the container through another handle.
|
||||
|
||||
~~~
|
||||
let mut xs = [1, 2, 3];
|
||||
{
|
||||
let _it = xs.iter();
|
||||
|
||||
// the vector is frozen for this scope, the compiler will statically
|
||||
// prevent modification
|
||||
}
|
||||
// the vector becomes unfrozen again at the end of the scope
|
||||
~~~
|
||||
|
||||
These semantics are due to most container iterators being implemented with `&`
|
||||
and `&mut`.
|
||||
|
||||
## Iterator adaptors
|
||||
|
||||
The `IteratorUtil` trait implements common algorithms as methods extending
|
||||
every `Iterator` implementation. For example, the `fold` method will accumulate
|
||||
the items yielded by an `Iterator` into a single value:
|
||||
|
||||
~~~
|
||||
let xs = [1, 9, 2, 3, 14, 12];
|
||||
let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
|
||||
assert_eq!(result, -41);
|
||||
~~~
|
||||
|
||||
Some adaptors return an adaptor object implementing the `Iterator` trait itself:
|
||||
|
||||
~~~
|
||||
let xs = [1, 9, 2, 3, 14, 12];
|
||||
let ys = [5, 2, 1, 8];
|
||||
let sum = xs.iter().chain_(ys.iter()).fold(0, |a, b| a + *b);
|
||||
assert_eq!(sum, 57);
|
||||
~~~
|
||||
|
||||
Note that some adaptors like the `chain_` method above use a trailing
|
||||
underscore to work around an issue with method resolve. The underscores will be
|
||||
dropped when they become unnecessary.
|
||||
|
||||
## For loops
|
||||
|
||||
The `for` loop syntax is currently in transition, and will switch from the old
|
||||
closure-based iteration protocol to iterator objects. For now, the `advance`
|
||||
adaptor is required as a compatibility shim to use iterators with for loops.
|
||||
|
||||
~~~
|
||||
let xs = [2, 3, 5, 7, 11, 13, 17];
|
||||
|
||||
// print out all the elements in the vector
|
||||
for xs.iter().advance |x| {
|
||||
println(x.to_str())
|
||||
}
|
||||
|
||||
// print out all but the first 3 elements in the vector
|
||||
for xs.iter().skip(3).advance |x| {
|
||||
println(x.to_str())
|
||||
}
|
||||
~~~
|
||||
|
||||
For loops are *often* used with a temporary iterator object, as above. They can
|
||||
also advance the state of an iterator in a mutable location:
|
||||
|
||||
~~~
|
||||
let xs = [1, 2, 3, 4, 5];
|
||||
let ys = ["foo", "bar", "baz", "foobar"];
|
||||
|
||||
// create an iterator yielding tuples of elements from both vectors
|
||||
let mut it = xs.iter().zip(ys.iter());
|
||||
|
||||
// print out the pairs of elements up to (&3, &"baz")
|
||||
for it.advance |(x, y)| {
|
||||
println(fmt!("%d %s", *x, *y));
|
||||
|
||||
if *x == 3 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// yield and print the last pair from the iterator
|
||||
println(fmt!("last: %?", it.next()));
|
||||
|
||||
// the iterator is now fully consumed
|
||||
assert!(it.next().is_none());
|
||||
~~~
|
@ -2,255 +2,269 @@
|
||||
|
||||
# Introduction
|
||||
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
557
doc/tutorial.md
557
doc/tutorial.md
File diff suppressed because it is too large
Load Diff
@ -7,4 +7,3 @@
|
||||
</center>
|
||||
|
||||
</div>
|
||||
|
||||
|
73
man/rustc.1
73
man/rustc.1
@ -1,4 +1,4 @@
|
||||
.TH RUSTC "1" "February 2013" "rustc 0.6" "User Commands"
|
||||
.TH RUSTC "1" "July 2013" "rustc 0.7" "User Commands"
|
||||
.SH NAME
|
||||
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.
|
||||
|
20
mk/clean.mk
20
mk/clean.mk
@ -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))
|
||||
|
@ -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
|
||||
|
102
mk/docs.mk
102
mk/docs.mk
@ -16,15 +16,8 @@ DOCS :=
|
||||
|
||||
|
||||
######################################################################
|
||||
# Pandoc (reference-manual related)
|
||||
# Docs, from pandoc, rustdoc (which runs pandoc), and node
|
||||
######################################################################
|
||||
ifeq ($(CFG_PANDOC),)
|
||||
$(info cfg: no pandoc found, omitting doc/rust.pdf)
|
||||
else
|
||||
|
||||
ifeq ($(CFG_NODE),)
|
||||
$(info cfg: no node found, omitting doc/tutorial.html)
|
||||
else
|
||||
|
||||
doc/rust.css: rust.css
|
||||
@$(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
|
||||
|
||||
|
||||
|
86
mk/host.mk
86
mk/host.mk
@ -28,8 +28,10 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
|
||||
$$(HLIB$(2)_H_$(4))/$(CFG_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), \
|
||||
|
@ -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
|
||||
|
105
mk/platform.mk
105
mk/platform.mk
@ -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)) \
|
||||
|
5
mk/pp.mk
5
mk/pp.mk
@ -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
165
mk/rt.mk
@ -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)))))
|
||||
|
@ -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))
|
||||
|
||||
|
20
mk/stage0.mk
20
mk/stage0.mk
@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \
|
||||
$(S)src/etc/get-snapshot.py $(MKFILE_DEPS)
|
||||
@$(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: $$@)
|
||||
|
65
mk/target.mk
65
mk/target.mk
@ -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:
|
||||
|
146
mk/tests.mk
146
mk/tests.mk
@ -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))))
|
||||
|
||||
|
71
mk/tools.mk
71
mk/tools.mk
@ -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))) \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,235 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[crate_type = "bin"];
|
||||
|
||||
#[no_core];
|
||||
|
||||
#[allow(vecs_implicitly_copyable)];
|
||||
#[allow(non_camel_case_types)];
|
||||
#[allow(deprecated_mode)];
|
||||
#[allow(deprecated_pattern)];
|
||||
|
||||
extern mod core(vers = "0.6");
|
||||
extern mod std(vers = "0.6");
|
||||
|
||||
use core::*;
|
||||
|
||||
|
||||
use std::getopts;
|
||||
use std::test;
|
||||
|
||||
use core::result::{Ok, Err};
|
||||
|
||||
use common::config;
|
||||
use common::mode_run_pass;
|
||||
use common::mode_run_fail;
|
||||
use common::mode_compile_fail;
|
||||
use common::mode_pretty;
|
||||
use common::mode_debug_info;
|
||||
use common::mode;
|
||||
use util::logv;
|
||||
|
||||
pub mod procsrv;
|
||||
pub mod util;
|
||||
pub mod header;
|
||||
pub mod runtest;
|
||||
pub mod common;
|
||||
pub mod errors;
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
let config = parse_config(args);
|
||||
log_config(config);
|
||||
run_tests(config);
|
||||
}
|
||||
|
||||
pub fn parse_config(args: ~[~str]) -> config {
|
||||
let opts =
|
||||
~[getopts::reqopt(~"compile-lib-path"),
|
||||
getopts::reqopt(~"run-lib-path"),
|
||||
getopts::reqopt(~"rustc-path"), getopts::reqopt(~"src-base"),
|
||||
getopts::reqopt(~"build-base"), getopts::reqopt(~"aux-base"),
|
||||
getopts::reqopt(~"stage-id"),
|
||||
getopts::reqopt(~"mode"), getopts::optflag(~"ignored"),
|
||||
getopts::optopt(~"runtool"), getopts::optopt(~"rustcflags"),
|
||||
getopts::optflag(~"verbose"),
|
||||
getopts::optopt(~"logfile"),
|
||||
getopts::optflag(~"jit"),
|
||||
getopts::optflag(~"newrt")];
|
||||
|
||||
assert!(!args.is_empty());
|
||||
let args_ = vec::tail(args);
|
||||
let matches =
|
||||
&match getopts::getopts(args_, opts) {
|
||||
Ok(m) => m,
|
||||
Err(f) => fail!(getopts::fail_str(f))
|
||||
};
|
||||
|
||||
fn opt_path(m: &getopts::Matches, nm: ~str) -> Path {
|
||||
Path(getopts::opt_str(m, nm))
|
||||
}
|
||||
|
||||
config {
|
||||
compile_lib_path: getopts::opt_str(matches, ~"compile-lib-path"),
|
||||
run_lib_path: getopts::opt_str(matches, ~"run-lib-path"),
|
||||
rustc_path: opt_path(matches, ~"rustc-path"),
|
||||
src_base: opt_path(matches, ~"src-base"),
|
||||
build_base: opt_path(matches, ~"build-base"),
|
||||
aux_base: opt_path(matches, ~"aux-base"),
|
||||
stage_id: getopts::opt_str(matches, ~"stage-id"),
|
||||
mode: str_mode(getopts::opt_str(matches, ~"mode")),
|
||||
run_ignored: getopts::opt_present(matches, ~"ignored"),
|
||||
filter:
|
||||
if vec::len(matches.free) > 0u {
|
||||
option::Some(matches.free[0])
|
||||
} else { option::None },
|
||||
logfile: getopts::opt_maybe_str(matches, ~"logfile").map(|s| Path(*s)),
|
||||
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
|
||||
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
|
||||
jit: getopts::opt_present(matches, ~"jit"),
|
||||
newrt: getopts::opt_present(matches, ~"newrt"),
|
||||
verbose: getopts::opt_present(matches, ~"verbose")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_config(config: config) {
|
||||
let c = config;
|
||||
logv(c, fmt!("configuration:"));
|
||||
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
||||
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
||||
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
||||
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
||||
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
||||
logv(c, fmt!("stage_id: %s", config.stage_id));
|
||||
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
||||
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
||||
logv(c, fmt!("filter: %s", opt_str(config.filter)));
|
||||
logv(c, fmt!("runtool: %s", opt_str(config.runtool)));
|
||||
logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags)));
|
||||
logv(c, fmt!("jit: %b", config.jit));
|
||||
logv(c, fmt!("newrt: %b", config.newrt));
|
||||
logv(c, fmt!("verbose: %b", config.verbose));
|
||||
logv(c, fmt!("\n"));
|
||||
}
|
||||
|
||||
pub fn opt_str(maybestr: Option<~str>) -> ~str {
|
||||
match maybestr { option::Some(s) => s, option::None => ~"(none)" }
|
||||
}
|
||||
|
||||
pub fn str_opt(maybestr: ~str) -> Option<~str> {
|
||||
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
||||
}
|
||||
|
||||
pub fn str_mode(s: ~str) -> mode {
|
||||
match s {
|
||||
~"compile-fail" => mode_compile_fail,
|
||||
~"run-fail" => mode_run_fail,
|
||||
~"run-pass" => mode_run_pass,
|
||||
~"pretty" => mode_pretty,
|
||||
~"debug-info" => mode_debug_info,
|
||||
_ => fail!(~"invalid mode")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode_str(mode: mode) -> ~str {
|
||||
match mode {
|
||||
mode_compile_fail => ~"compile-fail",
|
||||
mode_run_fail => ~"run-fail",
|
||||
mode_run_pass => ~"run-pass",
|
||||
mode_pretty => ~"pretty",
|
||||
mode_debug_info => ~"debug-info",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_tests(config: config) {
|
||||
let opts = test_opts(config);
|
||||
let tests = make_tests(config);
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
if !res { fail!(~"Some tests failed"); }
|
||||
}
|
||||
|
||||
pub fn test_opts(config: config) -> test::TestOpts {
|
||||
test::TestOpts {
|
||||
filter: config.filter,
|
||||
run_ignored: config.run_ignored,
|
||||
logfile: copy config.logfile,
|
||||
run_tests: true,
|
||||
run_benchmarks: false,
|
||||
save_results: option::None,
|
||||
compare_results: option::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_tests(config: config) -> ~[test::TestDescAndFn] {
|
||||
debug!("making tests from %s",
|
||||
config.src_base.to_str());
|
||||
let mut tests = ~[];
|
||||
for os::list_dir_path(&config.src_base).each |file| {
|
||||
let file = copy *file;
|
||||
debug!("inspecting file %s", file.to_str());
|
||||
if is_test(config, file) {
|
||||
tests.push(make_test(config, file))
|
||||
}
|
||||
}
|
||||
tests
|
||||
}
|
||||
|
||||
pub fn is_test(config: config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
mode_pretty => ~[~".rs"],
|
||||
_ => ~[~".rc", ~".rs"]
|
||||
};
|
||||
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
||||
let name = testfile.filename().get();
|
||||
|
||||
let mut valid = false;
|
||||
|
||||
for valid_extensions.each |ext| {
|
||||
if str::ends_with(name, *ext) { valid = true; }
|
||||
}
|
||||
|
||||
for invalid_prefixes.each |pre| {
|
||||
if str::starts_with(name, *pre) { valid = false; }
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
pub fn make_test(config: config, testfile: &Path) -> test::TestDescAndFn {
|
||||
test::TestDescAndFn {
|
||||
desc: test::TestDesc {
|
||||
name: make_test_name(config, testfile),
|
||||
ignore: header::is_test_ignored(config, testfile),
|
||||
should_fail: false
|
||||
},
|
||||
testfn: make_test_closure(config, testfile),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_test_name(config: config, testfile: &Path) -> test::TestName {
|
||||
test::DynTestName(fmt!("[%s] %s",
|
||||
mode_str(config.mode),
|
||||
testfile.to_str()))
|
||||
}
|
||||
|
||||
pub fn make_test_closure(config: config, testfile: &Path) -> test::TestFn {
|
||||
let testfile = testfile.to_str();
|
||||
test::DynTestFn(|| runtest::run(config, testfile))
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
275
src/compiletest/compiletest.rs
Normal file
275
src/compiletest/compiletest.rs
Normal file
@ -0,0 +1,275 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[crate_type = "bin"];
|
||||
|
||||
#[allow(non_camel_case_types)];
|
||||
|
||||
#[no_core]; // XXX: Remove after snapshot
|
||||
#[no_std];
|
||||
|
||||
extern mod core(name = "std", vers = "0.7");
|
||||
extern mod extra(name = "extra", vers = "0.7");
|
||||
|
||||
use core::prelude::*;
|
||||
use core::*;
|
||||
|
||||
use extra::getopts;
|
||||
use extra::test;
|
||||
|
||||
use core::result::{Ok, Err};
|
||||
|
||||
use common::config;
|
||||
use common::mode_run_pass;
|
||||
use common::mode_run_fail;
|
||||
use common::mode_compile_fail;
|
||||
use common::mode_pretty;
|
||||
use common::mode_debug_info;
|
||||
use common::mode;
|
||||
use util::logv;
|
||||
|
||||
pub mod procsrv;
|
||||
pub mod util;
|
||||
pub mod header;
|
||||
pub mod runtest;
|
||||
pub mod common;
|
||||
pub mod errors;
|
||||
|
||||
mod std {
|
||||
pub use core::cmp;
|
||||
pub use core::str;
|
||||
pub use core::sys;
|
||||
pub use core::unstable;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
let config = parse_config(args);
|
||||
log_config(&config);
|
||||
run_tests(&config);
|
||||
}
|
||||
|
||||
pub fn parse_config(args: ~[~str]) -> config {
|
||||
let opts =
|
||||
~[getopts::reqopt("compile-lib-path"),
|
||||
getopts::reqopt("run-lib-path"),
|
||||
getopts::reqopt("rustc-path"), getopts::reqopt("src-base"),
|
||||
getopts::reqopt("build-base"), getopts::reqopt("aux-base"),
|
||||
getopts::reqopt("stage-id"),
|
||||
getopts::reqopt("mode"), getopts::optflag("ignored"),
|
||||
getopts::optopt("runtool"), getopts::optopt("rustcflags"),
|
||||
getopts::optflag("verbose"),
|
||||
getopts::optopt("logfile"),
|
||||
getopts::optflag("jit"),
|
||||
getopts::optflag("newrt"),
|
||||
getopts::optopt("target"),
|
||||
getopts::optopt("adb-path"),
|
||||
getopts::optopt("adb-test-dir")
|
||||
];
|
||||
|
||||
assert!(!args.is_empty());
|
||||
let args_ = args.tail();
|
||||
let matches =
|
||||
&match getopts::getopts(args_, opts) {
|
||||
Ok(m) => m,
|
||||
Err(f) => fail!(getopts::fail_str(f))
|
||||
};
|
||||
|
||||
fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
|
||||
Path(getopts::opt_str(m, nm))
|
||||
}
|
||||
|
||||
config {
|
||||
compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
|
||||
run_lib_path: getopts::opt_str(matches, "run-lib-path"),
|
||||
rustc_path: opt_path(matches, "rustc-path"),
|
||||
src_base: opt_path(matches, "src-base"),
|
||||
build_base: opt_path(matches, "build-base"),
|
||||
aux_base: opt_path(matches, "aux-base"),
|
||||
stage_id: getopts::opt_str(matches, "stage-id"),
|
||||
mode: str_mode(getopts::opt_str(matches, "mode")),
|
||||
run_ignored: getopts::opt_present(matches, "ignored"),
|
||||
filter:
|
||||
if !matches.free.is_empty() {
|
||||
option::Some(copy matches.free[0])
|
||||
} else { option::None },
|
||||
logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)),
|
||||
runtool: getopts::opt_maybe_str(matches, "runtool"),
|
||||
rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
|
||||
jit: getopts::opt_present(matches, "jit"),
|
||||
newrt: getopts::opt_present(matches, "newrt"),
|
||||
target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
|
||||
adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
|
||||
adb_test_dir:
|
||||
opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
|
||||
adb_device_status:
|
||||
if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
|
||||
~"arm-linux-androideabi") {
|
||||
if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
|
||||
~"(none)" &&
|
||||
opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
|
||||
~"") { true }
|
||||
else { false }
|
||||
} else { false },
|
||||
verbose: getopts::opt_present(matches, "verbose")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_config(config: &config) {
|
||||
let c = config;
|
||||
logv(c, fmt!("configuration:"));
|
||||
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
||||
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
||||
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
||||
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
||||
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
||||
logv(c, fmt!("stage_id: %s", config.stage_id));
|
||||
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
||||
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
||||
logv(c, fmt!("filter: %s", opt_str(&config.filter)));
|
||||
logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
|
||||
logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
|
||||
logv(c, fmt!("jit: %b", config.jit));
|
||||
logv(c, fmt!("newrt: %b", config.newrt));
|
||||
logv(c, fmt!("target: %s", config.target));
|
||||
logv(c, fmt!("adb_path: %s", config.adb_path));
|
||||
logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
|
||||
logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
|
||||
logv(c, fmt!("verbose: %b", config.verbose));
|
||||
logv(c, fmt!("\n"));
|
||||
}
|
||||
|
||||
pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
|
||||
match *maybestr {
|
||||
option::None => "(none)",
|
||||
option::Some(ref s) => {
|
||||
let s: &'a str = *s;
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt_str2(maybestr: Option<~str>) -> ~str {
|
||||
match maybestr { None => ~"(none)", Some(s) => { s } }
|
||||
}
|
||||
|
||||
pub fn str_opt(maybestr: ~str) -> Option<~str> {
|
||||
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
||||
}
|
||||
|
||||
pub fn str_mode(s: ~str) -> mode {
|
||||
match s {
|
||||
~"compile-fail" => mode_compile_fail,
|
||||
~"run-fail" => mode_run_fail,
|
||||
~"run-pass" => mode_run_pass,
|
||||
~"pretty" => mode_pretty,
|
||||
~"debug-info" => mode_debug_info,
|
||||
_ => fail!("invalid mode")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode_str(mode: mode) -> ~str {
|
||||
match mode {
|
||||
mode_compile_fail => ~"compile-fail",
|
||||
mode_run_fail => ~"run-fail",
|
||||
mode_run_pass => ~"run-pass",
|
||||
mode_pretty => ~"pretty",
|
||||
mode_debug_info => ~"debug-info",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_tests(config: &config) {
|
||||
let opts = test_opts(config);
|
||||
let tests = make_tests(config);
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
if !res { fail!("Some tests failed"); }
|
||||
}
|
||||
|
||||
pub fn test_opts(config: &config) -> test::TestOpts {
|
||||
test::TestOpts {
|
||||
filter: copy config.filter,
|
||||
run_ignored: config.run_ignored,
|
||||
logfile: copy config.logfile,
|
||||
run_tests: true,
|
||||
run_benchmarks: false,
|
||||
save_results: option::None,
|
||||
compare_results: option::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
|
||||
debug!("making tests from %s",
|
||||
config.src_base.to_str());
|
||||
let mut tests = ~[];
|
||||
let dirs = os::list_dir_path(&config.src_base);
|
||||
for dirs.iter().advance |file| {
|
||||
let file = copy *file;
|
||||
debug!("inspecting file %s", file.to_str());
|
||||
if is_test(config, file) {
|
||||
tests.push(make_test(config, file))
|
||||
}
|
||||
}
|
||||
tests
|
||||
}
|
||||
|
||||
pub fn is_test(config: &config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
mode_pretty => ~[~".rs"],
|
||||
_ => ~[~".rc", ~".rs"]
|
||||
};
|
||||
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
||||
let name = testfile.filename().get();
|
||||
|
||||
let mut valid = false;
|
||||
|
||||
for valid_extensions.iter().advance |ext| {
|
||||
if name.ends_with(*ext) { valid = true; }
|
||||
}
|
||||
|
||||
for invalid_prefixes.iter().advance |pre| {
|
||||
if name.starts_with(*pre) { valid = false; }
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
pub fn make_test(config: &config, testfile: &Path) -> test::TestDescAndFn {
|
||||
test::TestDescAndFn {
|
||||
desc: test::TestDesc {
|
||||
name: make_test_name(config, testfile),
|
||||
ignore: header::is_test_ignored(config, testfile),
|
||||
should_fail: false
|
||||
},
|
||||
testfn: make_test_closure(config, testfile),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
|
||||
|
||||
// Try to elide redundant long paths
|
||||
fn shorten(path: &Path) -> ~str {
|
||||
let filename = path.filename();
|
||||
let dir = path.pop().filename();
|
||||
fmt!("%s/%s", dir.get_or_default(~""), filename.get_or_default(~""))
|
||||
}
|
||||
|
||||
test::DynTestName(fmt!("[%s] %s",
|
||||
mode_str(config.mode),
|
||||
shorten(testfile)))
|
||||
}
|
||||
|
||||
pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
|
||||
use core::cell::Cell;
|
||||
let config = Cell::new(copy *config);
|
||||
let testfile = Cell::new(testfile.to_str());
|
||||
test::DynTestFn(|| { runtest::run(config.take(), testfile.take()) })
|
||||
}
|
@ -11,8 +11,6 @@
|
||||
use core::prelude::*;
|
||||
|
||||
use core::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}];
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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); }
|
||||
}
|
||||
|
@ -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
36
src/etc/adb_run_wrapper.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#
|
||||
# usage : adb_run_wrapper [test dir - where test executables exist] [test executable]
|
||||
#
|
||||
|
||||
# Sometimes android shell produce exitcode "1 : Text File Busy"
|
||||
# Retry after $WAIT seconds, expecting resource cleaned-up
|
||||
WAIT=10
|
||||
PATH=$1
|
||||
if [ -d "$PATH" ]
|
||||
then
|
||||
shift
|
||||
RUN=$1
|
||||
|
||||
if [ ! -z "$RUN" ]
|
||||
then
|
||||
shift
|
||||
|
||||
L_RET=1
|
||||
L_COUNT=0
|
||||
cd $PATH
|
||||
while [ $L_RET -eq 1 ]
|
||||
do
|
||||
TEST_EXEC_ENV=22 LD_LIBRARY_PATH=$PATH $PATH/$RUN $@ 1>$PATH/$RUN.stdout 2>$PATH/$RUN.stderr
|
||||
L_RET=$?
|
||||
if [ $L_COUNT -gt 0 ]
|
||||
then
|
||||
/system/bin/sleep $WAIT
|
||||
/system/bin/sync
|
||||
fi
|
||||
L_COUNT=$((L_COUNT+1))
|
||||
done
|
||||
|
||||
echo $L_RET > $PATH/$RUN.exitcode
|
||||
|
||||
fi
|
||||
fi
|
@ -9,7 +9,7 @@ my $anchors = {};
|
||||
my $i = 0;
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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/
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -14,4 +14,3 @@ while (<>) {
|
||||
$indent -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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"])
|
||||
|
||||
|
||||
|
@ -243,4 +243,3 @@ int main() {
|
||||
extra_consts();
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
|
@ -96,4 +96,3 @@ def check_license(name, contents):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
Binary file not shown.
@ -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
|
||||
|
@ -33,6 +33,3 @@ for line in f.readlines():
|
||||
print("got download with ok hash")
|
||||
else:
|
||||
raise Exception("bad hash on download")
|
||||
|
||||
|
||||
|
||||
|
@ -77,4 +77,3 @@ while (my ($key, $substs) = each %funcs) {
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
@ -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))
|
||||
|
||||
|
@ -81,4 +81,3 @@ except UnicodeDecodeError, e:
|
||||
|
||||
|
||||
sys.exit(err)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1,5 +0,0 @@
|
||||
"Highlight the 100th text column
|
||||
"Feature became available in v7.3
|
||||
if version >= 703
|
||||
set colorcolumn=100
|
||||
endif
|
@ -1,4 +1,4 @@
|
||||
if exists('g:no_rust_conceal') || !has('conceal') || &enc != 'utf-8'
|
||||
if !exists('g:rust_conceal') || !has('conceal') || &enc != 'utf-8'
|
||||
finish
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
121
src/etc/ziggurat_tables.py
Executable file
@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
# xfail-license
|
||||
|
||||
# This creates the tables used for distributions implemented using the
|
||||
# ziggurat algorithm in `core::rand::distributions;`. They are
|
||||
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
|
||||
# They are changed rarely, so the generated file should be checked in
|
||||
# to git.
|
||||
#
|
||||
# It creates 3 tables: X as in the paper, F which is f(x_i), and
|
||||
# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached
|
||||
# values which is not done in that paper (but is done in other
|
||||
# variants). Note that the adZigR table is unnecessary because of
|
||||
# algebra.
|
||||
#
|
||||
# It is designed to be compatible with Python 2 and 3.
|
||||
|
||||
from math import exp, sqrt, log, floor
|
||||
import random
|
||||
|
||||
# The order should match the return value of `tables`
|
||||
TABLE_NAMES = ['X', 'F', 'F_DIFF']
|
||||
|
||||
# The actual length of the table is 1 more, to stop
|
||||
# index-out-of-bounds errors. This should match the bitwise operation
|
||||
# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and
|
||||
# *_V constants below depend on this value.
|
||||
TABLE_LEN = 256
|
||||
|
||||
# equivalent to `zigNorInit` in Doornik2005, but generalised to any
|
||||
# distribution. r = dR, v = dV, f = probability density function,
|
||||
# f_inv = inverse of f
|
||||
def tables(r, v, f, f_inv):
|
||||
# compute the x_i
|
||||
xvec = [0]*(TABLE_LEN+1)
|
||||
|
||||
xvec[0] = v / f(r)
|
||||
xvec[1] = r
|
||||
|
||||
for i in range(2, TABLE_LEN):
|
||||
last = xvec[i-1]
|
||||
xvec[i] = f_inv(v / last + f(last))
|
||||
|
||||
# cache the f's
|
||||
fvec = [0]*(TABLE_LEN+1)
|
||||
fdiff = [0]*(TABLE_LEN+1)
|
||||
for i in range(TABLE_LEN+1):
|
||||
fvec[i] = f(xvec[i])
|
||||
if i > 0:
|
||||
fdiff[i] = fvec[i] - fvec[i-1]
|
||||
|
||||
return xvec, fvec, fdiff
|
||||
|
||||
# Distributions
|
||||
# N(0, 1)
|
||||
def norm_f(x):
|
||||
return exp(-x*x/2.0)
|
||||
def norm_f_inv(y):
|
||||
return sqrt(-2.0*log(y))
|
||||
|
||||
NORM_R = 3.6541528853610088
|
||||
NORM_V = 0.00492867323399
|
||||
|
||||
NORM = tables(NORM_R, NORM_V,
|
||||
norm_f, norm_f_inv)
|
||||
|
||||
# Exp(1)
|
||||
def exp_f(x):
|
||||
return exp(-x)
|
||||
def exp_f_inv(y):
|
||||
return -log(y)
|
||||
|
||||
EXP_R = 7.69711747013104972
|
||||
EXP_V = 0.0039496598225815571993
|
||||
|
||||
EXP = tables(EXP_R, EXP_V,
|
||||
exp_f, exp_f_inv)
|
||||
|
||||
|
||||
# Output the tables/constants/types
|
||||
|
||||
def render_static(name, type, value):
|
||||
# no space or
|
||||
return 'pub static %s: %s =%s;\n' % (name, type, value)
|
||||
|
||||
# static `name`: [`type`, .. `len(values)`] =
|
||||
# [values[0], ..., values[3],
|
||||
# values[4], ..., values[7],
|
||||
# ... ];
|
||||
def render_table(name, values):
|
||||
rows = []
|
||||
# 4 values on each row
|
||||
for i in range(0, len(values), 4):
|
||||
row = values[i:i+4]
|
||||
rows.append(', '.join('%.18f' % f for f in row))
|
||||
|
||||
rendered = '\n [%s]' % ',\n '.join(rows)
|
||||
return render_static(name, '[f64, .. %d]' % len(values), rendered)
|
||||
|
||||
|
||||
with open('ziggurat_tables.rs', 'w') as f:
|
||||
f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tables for distributions which are sampled using the ziggurat
|
||||
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||
|
||||
pub type ZigTable = &\'static [f64, .. %d];
|
||||
''' % (TABLE_LEN + 1))
|
||||
for name, tables, r in [('NORM', NORM, NORM_R),
|
||||
('EXP', EXP, EXP_R)]:
|
||||
f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r))
|
||||
for (tabname, table) in zip(TABLE_NAMES, tables):
|
||||
f.write(render_table('ZIG_%s_%s' % (name, tabname), table))
|
103
src/etc/zsh/_rust
Normal file
103
src/etc/zsh/_rust
Normal file
@ -0,0 +1,103 @@
|
||||
#compdef rustc
|
||||
|
||||
local -a _rustc_opts_switches _rustc_opts_lint _rustc_opts_debug
|
||||
|
||||
typeset -A opt_args
|
||||
|
||||
_rustc_opts_switches=(
|
||||
--bin'[Compile an executable crate (default)]'
|
||||
-c'[Compile and assemble, but do not link]'
|
||||
--cfg'[Configure the compilation environment]'
|
||||
--emit-llvm'[Produce an LLVM bitcode file]'
|
||||
{-h,--help}'[Display this message]'
|
||||
-L'[Add a directory to the library search path]'
|
||||
--lib'[Compile a library crate]'
|
||||
--linker'[Program to use for linking instead of the default.]'
|
||||
--link-args'[FLAGS is a space-separated list of flags passed to the linker]'
|
||||
--ls'[List the symbols defined by a library crate]'
|
||||
--no-trans'[Run all passes except translation; no output]'
|
||||
-O'[Equivalent to --opt-level=2]'
|
||||
-o'[Write output to <filename>]'
|
||||
--opt-level'[Optimize with possible levels 0-3]'
|
||||
--out-dir'[Write output to compiler-chosen filename in <dir>]'
|
||||
--parse-only'[Parse only; do not compile, assemble, or link]'
|
||||
--pretty'[Pretty-print the input instead of compiling]'
|
||||
-S'[Compile only; do not assemble or link]'
|
||||
--save-temps'[Write intermediate files (.bc, .opt.bc, .o) in addition to normal output]'
|
||||
--sysroot'[Override the system root]'
|
||||
--test'[Build a test harness]'
|
||||
--target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]'
|
||||
--target-feature'[Target specific attributes (llc -mattr=help for detail)]'
|
||||
--android-cross-path'[The path to the Android NDK]'
|
||||
{-v,--version}'[Print version info and exit]'
|
||||
)
|
||||
_rustc_opts_lint=(
|
||||
'path-statement[path statements with no effect]'
|
||||
'deprecated-pattern[warn about deprecated uses of pattern bindings]'
|
||||
'non-implicitly-copyable-typarams[passing non implicitly copyable types as copy type params]'
|
||||
'missing-trait-doc[detects missing documentation for traits]'
|
||||
'missing-struct-doc[detects missing documentation for structs]'
|
||||
'ctypes[proper use of core::libc types in foreign modules]'
|
||||
'implicit-copies[implicit copies of non implicitly copyable data]'
|
||||
"unused-mut[detect mut variables which don't need to be mutable]"
|
||||
'unused-imports[imports that are never used]'
|
||||
'heap-memory[use of any (~ type or @ type) heap memory]'
|
||||
'default-methods[allow default methods]'
|
||||
'unused-variable[detect variables which are not used in any way]'
|
||||
'dead-assignment[detect assignments that will never be read]'
|
||||
'unrecognized-lint[unrecognized lint attribute]'
|
||||
'type-limits[comparisons made useless by limits of the types involved]'
|
||||
'unused-unsafe[unnecessary use of an `unsafe` block]'
|
||||
'while-true[suggest using loop { } instead of while(true) { }]'
|
||||
'non-camel-case-types[types, variants and traits should have camel case names]'
|
||||
'managed-heap-memory[use of managed (@ type) heap memory]'
|
||||
'unnecessary-allocation[detects unnecessary allocations that can be eliminated]'
|
||||
'owned-heap-memory[use of owned (~ type) heap memory]'
|
||||
)
|
||||
|
||||
_rustc_opts_debug=(
|
||||
'verbose:in general, enable more debug printouts'
|
||||
'time-passes:measure time of each rustc pass'
|
||||
'count-llvm-insns:count where LLVM instrs originate'
|
||||
'time-llvm-passes:measure time of each LLVM pass'
|
||||
'trans-stats:gather trans statistics'
|
||||
'asm-comments:generate comments into the assembly (may change behavior)'
|
||||
'no-verify:skip LLVM verification'
|
||||
'trace:emit trace logs'
|
||||
'coherence:perform coherence checking'
|
||||
'borrowck-stats:gather borrowck statistics'
|
||||
"borrowck-note-pure:note where purity is req'd"
|
||||
"borrowck-note-loan:note where loans are req'd"
|
||||
'no-landing-pads:omit landing pads for unwinding'
|
||||
'debug-llvm:enable debug output from LLVM'
|
||||
'count-type-sizes:count the sizes of aggregate types'
|
||||
'meta-stats:gather metadata statistics'
|
||||
'no-opt:do not optimize, even if -O is passed'
|
||||
'no-monomorphic-collapse:do not collapse template instantiations'
|
||||
'print-link-args:Print the arguments passed to the linker'
|
||||
'gc:Garbage collect shared data (experimental)'
|
||||
'jit:Execute using JIT (experimental)'
|
||||
'extra-debug-info:Extra debugging info (experimental)'
|
||||
'debug-info:Produce debug info (experimental)'
|
||||
'static:Use or produce static libraries or binaries (experimental)'
|
||||
'no-debug-borrows:do not show where borrow checks fail'
|
||||
'lint-llvm:Run the LLVM lint pass on the pre-optimization IR'
|
||||
)
|
||||
|
||||
_rustc_opts_fun_lint(){
|
||||
_values -s , 'options' \
|
||||
"$_rustc_opts_lint[@]"
|
||||
}
|
||||
|
||||
_rustc_opts_fun_debug(){
|
||||
_describe 'options' _rustc_opts_debug
|
||||
}
|
||||
|
||||
_arguments -s : \
|
||||
'(-W --warn)'{-W,--warn}'[Set lint warnings]:lint options:_rustc_opts_fun_lint' \
|
||||
'(-A --allow)'{-A,--allow}'[Set lint allowed]:lint options:_rustc_opts_fun_lint' \
|
||||
'(-D --deny)'{-D,--deny}'[Set lint denied]:lint options:_rustc_opts_fun_lint' \
|
||||
'(-F --forbid)'{-F,--forbid}'[Set lint forbidden]:lint options:_rustc_opts_fun_lint' \
|
||||
'*-Z[Set internal debugging options]:debug options:_rustc_opts_fun_debug' \
|
||||
"$_rustc_opts_switches[@]" \
|
||||
'*::files:_files -g "*.rs"'
|
@ -1,321 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Managed vectors
|
||||
|
||||
use cast::transmute;
|
||||
use kinds::Copy;
|
||||
use iter;
|
||||
use option::Option;
|
||||
use ptr::addr_of;
|
||||
use sys;
|
||||
use uint;
|
||||
use vec;
|
||||
|
||||
/// Code for dealing with @-vectors. This is pretty incomplete, and
|
||||
/// contains a bunch of duplication from the code for ~-vectors.
|
||||
|
||||
pub mod rustrt {
|
||||
use libc;
|
||||
use sys;
|
||||
use vec;
|
||||
|
||||
#[abi = "cdecl"]
|
||||
#[link_name = "rustrt"]
|
||||
pub extern {
|
||||
pub unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
|
||||
++v: **vec::raw::VecRepr,
|
||||
++n: libc::size_t);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of elements the vector can hold without reallocating
|
||||
#[inline(always)]
|
||||
pub fn capacity<T>(v: @[T]) -> uint {
|
||||
unsafe {
|
||||
let repr: **raw::VecRepr =
|
||||
::cast::reinterpret_cast(&addr_of(&v));
|
||||
(**repr).unboxed.alloc / sys::size_of::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a vector by calling a provided function with an argument
|
||||
* function that pushes an element to the back of a vector.
|
||||
* This version takes an initial size for the vector.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * size - An initial size of the vector to reserve
|
||||
* * builder - A function that will construct the vector. It recieves
|
||||
* as an argument a function that will push an element
|
||||
* onto the vector being constructed.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn build_sized<A>(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] {
|
||||
let mut vec: @[A] = @[];
|
||||
unsafe { raw::reserve(&mut vec, size); }
|
||||
builder(|+x| unsafe { raw::push(&mut vec, x) });
|
||||
return unsafe { transmute(vec) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a vector by calling a provided function with an argument
|
||||
* function that pushes an element to the back of a vector.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * builder - A function that will construct the vector. It recieves
|
||||
* as an argument a function that will push an element
|
||||
* onto the vector being constructed.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn build<A>(builder: &fn(push: &fn(v: A))) -> @[A] {
|
||||
build_sized(4, builder)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a vector by calling a provided function with an argument
|
||||
* function that pushes an element to the back of a vector.
|
||||
* This version takes an initial size for the vector.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * size - An option, maybe containing initial size of the vector to reserve
|
||||
* * builder - A function that will construct the vector. It recieves
|
||||
* as an argument a function that will push an element
|
||||
* onto the vector being constructed.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn build_sized_opt<A>(size: Option<uint>,
|
||||
builder: &fn(push: &fn(v: A)))
|
||||
-> @[A] {
|
||||
build_sized(size.get_or_default(4), builder)
|
||||
}
|
||||
|
||||
// Appending
|
||||
#[inline(always)]
|
||||
pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] {
|
||||
do build_sized(lhs.len() + rhs.len()) |push| {
|
||||
for vec::each(lhs) |x| { push(*x); }
|
||||
for uint::range(0, rhs.len()) |i| { push(rhs[i]); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Apply a function to each element of a vector and return the results
|
||||
pub fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] {
|
||||
do build_sized(v.len()) |push| {
|
||||
for vec::each(v) |elem| {
|
||||
push(f(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes an immutable vector.
|
||||
*
|
||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
||||
* to the value returned by the function `op`.
|
||||
*/
|
||||
pub fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> @[T] {
|
||||
do build_sized(n_elts) |push| {
|
||||
let mut i: uint = 0u;
|
||||
while i < n_elts { push(op(i)); i += 1u; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes an immutable vector.
|
||||
*
|
||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
||||
* to the value `t`.
|
||||
*/
|
||||
pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> @[T] {
|
||||
do build_sized(n_elts) |push| {
|
||||
let mut i: uint = 0u;
|
||||
while i < n_elts { push(copy t); i += 1u; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes an immutable managed vector by moving all the
|
||||
* elements from an owned vector.
|
||||
*/
|
||||
pub fn from_owned<T>(v: ~[T]) -> @[T] {
|
||||
let mut av = @[];
|
||||
unsafe {
|
||||
raw::reserve(&mut av, v.len());
|
||||
do vec::consume(v) |_i, x| {
|
||||
raw::push(&mut av, x);
|
||||
}
|
||||
transmute(av)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes an immutable managed vector by copying all the
|
||||
* elements of a slice.
|
||||
*/
|
||||
pub fn from_slice<T:Copy>(v: &[T]) -> @[T] {
|
||||
from_fn(v.len(), |i| v[i])
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
pub mod traits {
|
||||
use at_vec::append;
|
||||
use kinds::Copy;
|
||||
use ops::Add;
|
||||
|
||||
impl<'self,T:Copy> Add<&'self const [T],@[T]> for @[T] {
|
||||
#[inline(always)]
|
||||
fn add(&self, rhs: & &'self const [T]) -> @[T] {
|
||||
append(*self, (*rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod traits {}
|
||||
|
||||
pub mod raw {
|
||||
use at_vec::{capacity, rustrt};
|
||||
use cast::transmute;
|
||||
use libc;
|
||||
use unstable::intrinsics::{move_val_init};
|
||||
use ptr::addr_of;
|
||||
use ptr;
|
||||
use sys;
|
||||
use uint;
|
||||
use vec;
|
||||
|
||||
pub type VecRepr = vec::raw::VecRepr;
|
||||
pub type SliceRepr = vec::raw::SliceRepr;
|
||||
|
||||
/**
|
||||
* Sets the length of a vector
|
||||
*
|
||||
* This will explicitly set the size of the vector, without actually
|
||||
* modifing its buffers, so it is up to the caller to ensure that
|
||||
* the vector is actually the specified size.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub unsafe fn set_len<T>(v: @[T], new_len: uint) {
|
||||
let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(&v));
|
||||
(**repr).unboxed.fill = new_len * sys::size_of::<T>();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn push<T>(v: &mut @[T], initval: T) {
|
||||
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
|
||||
let fill = (**repr).unboxed.fill;
|
||||
if (**repr).unboxed.alloc > fill {
|
||||
push_fast(v, initval);
|
||||
}
|
||||
else {
|
||||
push_slow(v, initval);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)] // really pretty please
|
||||
pub unsafe fn push_fast<T>(v: &mut @[T], initval: T) {
|
||||
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
|
||||
let fill = (**repr).unboxed.fill;
|
||||
(**repr).unboxed.fill += sys::size_of::<T>();
|
||||
let p = addr_of(&((**repr).unboxed.data));
|
||||
let p = ptr::offset(p, fill) as *mut T;
|
||||
move_val_init(&mut(*p), initval);
|
||||
}
|
||||
|
||||
pub unsafe fn push_slow<T>(v: &mut @[T], initval: T) {
|
||||
reserve_at_least(&mut *v, v.len() + 1u);
|
||||
push_fast(v, initval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves capacity for exactly `n` elements in the given vector.
|
||||
*
|
||||
* If the capacity for `v` is already equal to or greater than the
|
||||
* requested capacity, then no action is taken.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * v - A vector
|
||||
* * n - The number of elements to reserve space for
|
||||
*/
|
||||
pub unsafe fn reserve<T>(v: &mut @[T], n: uint) {
|
||||
// Only make the (slow) call into the runtime if we have to
|
||||
if capacity(*v) < n {
|
||||
let ptr: **VecRepr = transmute(v);
|
||||
rustrt::vec_reserve_shared_actual(sys::get_type_desc::<T>(),
|
||||
ptr, n as libc::size_t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves capacity for at least `n` elements in the given vector.
|
||||
*
|
||||
* This function will over-allocate in order to amortize the
|
||||
* allocation costs in scenarios where the caller may need to
|
||||
* repeatedly reserve additional space.
|
||||
*
|
||||
* If the capacity for `v` is already equal to or greater than the
|
||||
* requested capacity, then no action is taken.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * v - A vector
|
||||
* * n - The number of elements to reserve space for
|
||||
*/
|
||||
pub unsafe fn reserve_at_least<T>(v: &mut @[T], n: uint) {
|
||||
reserve(v, uint::next_power_of_two(n));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test() {
|
||||
// Some code that could use that, then:
|
||||
fn seq_range(lo: uint, hi: uint) -> @[uint] {
|
||||
do build |push| {
|
||||
for uint::range(lo, hi) |i| {
|
||||
push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(seq_range(10, 15), @[10, 11, 12, 13, 14]);
|
||||
assert!(from_fn(5, |x| x+1) == @[1, 2, 3, 4, 5]);
|
||||
assert!(from_elem(5, 3.14) == @[3.14, 3.14, 3.14, 3.14, 3.14]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn append_test() {
|
||||
assert!(@[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_from_owned() {
|
||||
assert!(from_owned::<int>(~[]) == @[]);
|
||||
assert!(from_owned(~[true]) == @[true]);
|
||||
assert!(from_owned(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
|
||||
assert!(from_owned(~[~"abc", ~"123"]) == @[~"abc", ~"123"]);
|
||||
assert!(from_owned(~[~[42]]) == @[~[42]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_from_slice() {
|
||||
assert!(from_slice::<int>([]) == @[]);
|
||||
assert!(from_slice([true]) == @[true]);
|
||||
assert!(from_slice([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]);
|
||||
assert!(from_slice([@"abc", @"123"]) == @[@"abc", @"123"]);
|
||||
assert!(from_slice([@[42]]) == @[@[42]]);
|
||||
}
|
||||
|
@ -1,112 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Boolean logic
|
||||
|
||||
use option::{None, Option, Some};
|
||||
use from_str::FromStr;
|
||||
|
||||
#[cfg(notest)] use cmp;
|
||||
|
||||
/// Negation / inverse
|
||||
pub fn not(v: bool) -> bool { !v }
|
||||
|
||||
/// Conjunction
|
||||
pub fn and(a: bool, b: bool) -> bool { a && b }
|
||||
|
||||
/// Disjunction
|
||||
pub fn or(a: bool, b: bool) -> bool { a || b }
|
||||
|
||||
/**
|
||||
* Exclusive or
|
||||
*
|
||||
* Identical to `or(and(a, not(b)), and(not(a), b))`
|
||||
*/
|
||||
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }
|
||||
|
||||
/// Implication in the logic, i.e. from `a` follows `b`
|
||||
pub fn implies(a: bool, b: bool) -> bool { !a || b }
|
||||
|
||||
/// true if truth values `a` and `b` are indistinguishable in the logic
|
||||
pub fn eq(a: bool, b: bool) -> bool { a == b }
|
||||
|
||||
/// true if truth values `a` and `b` are distinguishable in the logic
|
||||
pub fn ne(a: bool, b: bool) -> bool { a != b }
|
||||
|
||||
/// true if `v` represents truth in the logic
|
||||
pub fn is_true(v: bool) -> bool { v }
|
||||
|
||||
/// true if `v` represents falsehood in the logic
|
||||
pub fn is_false(v: bool) -> bool { !v }
|
||||
|
||||
/// Parse logic value from `s`
|
||||
impl FromStr for bool {
|
||||
fn from_str(s: &str) -> Option<bool> {
|
||||
if s == "true" {
|
||||
Some(true)
|
||||
} else if s == "false" {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `v` into a string
|
||||
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }
|
||||
|
||||
/**
|
||||
* Iterates over all truth values by passing them to `blk` in an unspecified
|
||||
* order
|
||||
*/
|
||||
pub fn all_values(blk: &fn(v: bool)) {
|
||||
blk(true);
|
||||
blk(false);
|
||||
}
|
||||
|
||||
/// converts truth value to an 8 bit byte
|
||||
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }
|
||||
|
||||
#[cfg(notest)]
|
||||
impl cmp::Eq for bool {
|
||||
fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
|
||||
fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bool_from_str() {
|
||||
use from_str::FromStr;
|
||||
|
||||
do all_values |v| {
|
||||
assert!(Some(v) == FromStr::from_str(to_str(v)))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bool_to_str() {
|
||||
assert!(to_str(false) == ~"false");
|
||||
assert!(to_str(true) == ~"true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bool_to_bit() {
|
||||
do all_values |v| {
|
||||
assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
@ -1,154 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Unsafe casting functions
|
||||
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
#[link_name = "rusti"]
|
||||
pub extern "rust-intrinsic" {
|
||||
fn forget<T>(+x: T);
|
||||
fn reinterpret_cast<T, U>(&&e: T) -> U;
|
||||
}
|
||||
}
|
||||
|
||||
/// Casts the value at `src` to U. The two types must have the same length.
|
||||
#[inline(always)]
|
||||
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
|
||||
rusti::reinterpret_cast(*src)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a thing into the void
|
||||
*
|
||||
* The forget function will take ownership of the provided value but neglect
|
||||
* to run any required cleanup or memory-management operations on it. This
|
||||
* can be used for various acts of magick, particularly when using
|
||||
* reinterpret_cast on pointer types.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub unsafe fn forget<T>(thing: T) { rusti::forget(thing); }
|
||||
|
||||
/**
|
||||
* Force-increment the reference count on a shared box. If used
|
||||
* carelessly, this can leak the box. Use this in conjunction with transmute
|
||||
* and/or reinterpret_cast when such calls would otherwise scramble a box's
|
||||
* reference count
|
||||
*/
|
||||
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
|
||||
|
||||
/**
|
||||
* Transform a value of one type into a value of another type.
|
||||
* Both types must have the same size and alignment.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* assert!(transmute("L") == ~[76u8, 0u8]);
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute<L, G>(thing: L) -> G {
|
||||
let newthing: G = reinterpret_cast(&thing);
|
||||
forget(thing);
|
||||
newthing
|
||||
}
|
||||
|
||||
/// Coerce an immutable reference to be mutable.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }
|
||||
|
||||
/// Coerce a mutable reference to be immutable.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_immut<'a,T>(ptr: &'a mut T) -> &'a T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
/// Coerce a borrowed pointer to have an arbitrary associated region.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
/// Coerce an immutable reference to be mutable.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
/// Coerce an immutable reference to be mutable.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
|
||||
transmute(ptr)
|
||||
}
|
||||
|
||||
/// Transforms lifetime of the second pointer to match the first.
|
||||
#[inline(always)]
|
||||
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
|
||||
transmute_region(ptr)
|
||||
}
|
||||
|
||||
/// Transforms lifetime of the second pointer to match the first.
|
||||
#[inline(always)]
|
||||
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
|
||||
transmute_region(ptr)
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Tests
|
||||
****************************************************************************/
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use cast::{bump_box_refcount, reinterpret_cast, transmute};
|
||||
|
||||
#[test]
|
||||
pub fn test_reinterpret_cast() {
|
||||
assert!(1u == unsafe { reinterpret_cast(&1) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bump_box_refcount() {
|
||||
unsafe {
|
||||
let box = @~"box box box"; // refcount 1
|
||||
bump_box_refcount(box); // refcount 2
|
||||
let ptr: *int = transmute(box); // refcount 2
|
||||
let _box1: @~str = reinterpret_cast(&ptr);
|
||||
let _box2: @~str = reinterpret_cast(&ptr);
|
||||
assert!(*_box1 == ~"box box box");
|
||||
assert!(*_box2 == ~"box box box");
|
||||
// Will destroy _box1 and _box2. Without the bump, this would
|
||||
// use-after-free. With too many bumps, it would leak.
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_transmute() {
|
||||
use managed::raw::BoxRepr;
|
||||
unsafe {
|
||||
let x = @100u8;
|
||||
let x: *BoxRepr = transmute(x);
|
||||
assert!((*x).data == 100);
|
||||
let _x: @int = transmute(x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_transmute2() {
|
||||
unsafe {
|
||||
assert!(~[76u8, 0u8] == transmute(~"L"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A mutable, nullable memory location
|
||||
|
||||
use cast::transmute;
|
||||
use prelude::*;
|
||||
|
||||
/*
|
||||
A dynamic, mutable location.
|
||||
|
||||
Similar to a mutable option type, but friendlier.
|
||||
*/
|
||||
|
||||
pub struct Cell<T> {
|
||||
mut value: Option<T>
|
||||
}
|
||||
|
||||
impl<T:cmp::Eq> cmp::Eq for Cell<T> {
|
||||
fn eq(&self, other: &Cell<T>) -> bool {
|
||||
unsafe {
|
||||
let frozen_self: &Option<T> = transmute(&mut self.value);
|
||||
let frozen_other: &Option<T> = transmute(&mut other.value);
|
||||
frozen_self == frozen_other
|
||||
}
|
||||
}
|
||||
fn ne(&self, other: &Cell<T>) -> bool { !self.eq(other) }
|
||||
}
|
||||
|
||||
/// Creates a new full cell with the given value.
|
||||
pub fn Cell<T>(value: T) -> Cell<T> {
|
||||
Cell { value: Some(value) }
|
||||
}
|
||||
|
||||
pub fn empty_cell<T>() -> Cell<T> {
|
||||
Cell { value: None }
|
||||
}
|
||||
|
||||
pub impl<T> Cell<T> {
|
||||
/// Yields the value, failing if the cell is empty.
|
||||
fn take(&self) -> T {
|
||||
if self.is_empty() {
|
||||
fail!(~"attempt to take an empty cell");
|
||||
}
|
||||
|
||||
let mut value = None;
|
||||
value <-> self.value;
|
||||
value.unwrap()
|
||||
}
|
||||
|
||||
/// Returns the value, failing if the cell is full.
|
||||
fn put_back(&self, value: T) {
|
||||
if !self.is_empty() {
|
||||
fail!(~"attempt to put a value back into a full cell");
|
||||
}
|
||||
self.value = Some(value);
|
||||
}
|
||||
|
||||
/// Returns true if the cell is empty and false if the cell is full.
|
||||
fn is_empty(&self) -> bool {
|
||||
self.value.is_none()
|
||||
}
|
||||
|
||||
// Calls a closure with a reference to the value.
|
||||
fn with_ref<R>(&self, op: &fn(v: &T) -> R) -> R {
|
||||
let v = self.take();
|
||||
let r = op(&v);
|
||||
self.put_back(v);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let value_cell = Cell(~10);
|
||||
assert!(!value_cell.is_empty());
|
||||
let value = value_cell.take();
|
||||
assert!(value == ~10);
|
||||
assert!(value_cell.is_empty());
|
||||
value_cell.put_back(value);
|
||||
assert!(!value_cell.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
#[ignore(cfg(windows))]
|
||||
fn test_take_empty() {
|
||||
let value_cell = empty_cell::<~int>();
|
||||
value_cell.take();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
#[ignore(cfg(windows))]
|
||||
fn test_put_back_non_empty() {
|
||||
let value_cell = Cell(~10);
|
||||
value_cell.put_back(~20);
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Utilities for manipulating the char type
|
||||
|
||||
use option::{None, Option, Some};
|
||||
use str;
|
||||
use u32;
|
||||
use uint;
|
||||
use unicode;
|
||||
|
||||
#[cfg(notest)] use cmp::Eq;
|
||||
|
||||
/*
|
||||
Lu Uppercase_Letter an uppercase letter
|
||||
Ll Lowercase_Letter a lowercase letter
|
||||
Lt Titlecase_Letter a digraphic character, with first part uppercase
|
||||
Lm Modifier_Letter a modifier letter
|
||||
Lo Other_Letter other letters, including syllables and ideographs
|
||||
Mn Nonspacing_Mark a nonspacing combining mark (zero advance width)
|
||||
Mc Spacing_Mark a spacing combining mark (positive advance width)
|
||||
Me Enclosing_Mark an enclosing combining mark
|
||||
Nd Decimal_Number a decimal digit
|
||||
Nl Letter_Number a letterlike numeric character
|
||||
No Other_Number a numeric character of other type
|
||||
Pc Connector_Punctuation a connecting punctuation mark, like a tie
|
||||
Pd Dash_Punctuation a dash or hyphen punctuation mark
|
||||
Ps Open_Punctuation an opening punctuation mark (of a pair)
|
||||
Pe Close_Punctuation a closing punctuation mark (of a pair)
|
||||
Pi Initial_Punctuation an initial quotation mark
|
||||
Pf Final_Punctuation a final quotation mark
|
||||
Po Other_Punctuation a punctuation mark of other type
|
||||
Sm Math_Symbol a symbol of primarily mathematical use
|
||||
Sc Currency_Symbol a currency sign
|
||||
Sk Modifier_Symbol a non-letterlike modifier symbol
|
||||
So Other_Symbol a symbol of other type
|
||||
Zs Space_Separator a space character (of various non-zero widths)
|
||||
Zl Line_Separator U+2028 LINE SEPARATOR only
|
||||
Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only
|
||||
Cc Control a C0 or C1 control code
|
||||
Cf Format a format control character
|
||||
Cs Surrogate a surrogate code point
|
||||
Co Private_Use a private-use character
|
||||
Cn Unassigned a reserved unassigned code point or a noncharacter
|
||||
*/
|
||||
|
||||
pub use is_alphabetic = unicode::derived_property::Alphabetic;
|
||||
pub use is_XID_start = unicode::derived_property::XID_Start;
|
||||
pub use is_XID_continue = unicode::derived_property::XID_Continue;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether a character is in lower case, defined
|
||||
* in terms of the Unicode General Category 'Ll'
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_lowercase(c: char) -> bool {
|
||||
return unicode::general_category::Ll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a character is in upper case, defined
|
||||
* in terms of the Unicode General Category 'Lu'.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_uppercase(c: char) -> bool {
|
||||
return unicode::general_category::Lu(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a character is whitespace. Whitespace is defined in
|
||||
* terms of the Unicode General Categories 'Zs', 'Zl', 'Zp'
|
||||
* additional 'Cc'-category control codes in the range [0x09, 0x0d]
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_whitespace(c: char) -> bool {
|
||||
return ('\x09' <= c && c <= '\x0d')
|
||||
|| unicode::general_category::Zs(c)
|
||||
|| unicode::general_category::Zl(c)
|
||||
|| unicode::general_category::Zp(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a character is alphanumeric. Alphanumericness is
|
||||
* defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No'
|
||||
* and the Derived Core Property 'Alphabetic'.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_alphanumeric(c: char) -> bool {
|
||||
return unicode::derived_property::Alphabetic(c) ||
|
||||
unicode::general_category::Nd(c) ||
|
||||
unicode::general_category::Nl(c) ||
|
||||
unicode::general_category::No(c);
|
||||
}
|
||||
|
||||
/// Indicates whether the character is an ASCII character
|
||||
#[inline(always)]
|
||||
pub fn is_ascii(c: char) -> bool {
|
||||
c - ('\x7F' & c) == '\x00'
|
||||
}
|
||||
|
||||
/// Indicates whether the character is numeric (Nd, Nl, or No)
|
||||
#[inline(always)]
|
||||
pub fn is_digit(c: char) -> bool {
|
||||
return unicode::general_category::Nd(c) ||
|
||||
unicode::general_category::Nl(c) ||
|
||||
unicode::general_category::No(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a character parses as a numeric digit in the given radix.
|
||||
* Compared to `is_digit()`, this function only recognizes the ascii
|
||||
* characters `0-9`, `a-z` and `A-Z`.
|
||||
*
|
||||
* Returns `true` if `c` is a valid digit under `radix`, and `false`
|
||||
* otherwise.
|
||||
*
|
||||
* Fails if given a `radix` > 36.
|
||||
*
|
||||
* Note: This just wraps `to_digit()`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_digit_radix(c: char, radix: uint) -> bool {
|
||||
match to_digit(c, radix) {
|
||||
Some(_) => true,
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a char to the corresponding digit.
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* If `c` is between '0' and '9', the corresponding value
|
||||
* between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is
|
||||
* 'b' or 'B', 11, etc. Returns none if the char does not
|
||||
* refer to a digit in the given radix.
|
||||
*
|
||||
* # Failure
|
||||
* Fails if given a `radix` outside the range `[0..36]`.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn to_digit(c: char, radix: uint) -> Option<uint> {
|
||||
if radix > 36 {
|
||||
fail!(fmt!("to_digit: radix %? is to high (maximum 36)", radix));
|
||||
}
|
||||
let val = match c {
|
||||
'0' .. '9' => c as uint - ('0' as uint),
|
||||
'a' .. 'z' => c as uint + 10u - ('a' as uint),
|
||||
'A' .. 'Z' => c as uint + 10u - ('A' as uint),
|
||||
_ => return None
|
||||
};
|
||||
if val < radix { Some(val) }
|
||||
else { None }
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number to the ascii character representing it.
|
||||
*
|
||||
* Returns `Some(char)` if `num` represents one digit under `radix`,
|
||||
* using one character of `0-9` or `a-z`, or `None` if it doesn't.
|
||||
*
|
||||
* Fails if given an `radix` > 36.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
|
||||
if radix > 36 {
|
||||
fail!(fmt!("from_digit: radix %? is to high (maximum 36)", num));
|
||||
}
|
||||
if num < radix {
|
||||
if num < 10 {
|
||||
Some(('0' as uint + num) as char)
|
||||
} else {
|
||||
Some(('a' as uint + num - 10u) as char)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hexadecimal unicode escape of a char.
|
||||
*
|
||||
* The rules are as follows:
|
||||
*
|
||||
* - chars in [0,0xff] get 2-digit escapes: `\\xNN`
|
||||
* - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
|
||||
* - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
|
||||
*/
|
||||
pub fn escape_unicode(c: char) -> ~str {
|
||||
let s = u32::to_str_radix(c as u32, 16u);
|
||||
let (c, pad) = (if c <= '\xff' { ('x', 2u) }
|
||||
else if c <= '\uffff' { ('u', 4u) }
|
||||
else { ('U', 8u) });
|
||||
assert!(str::len(s) <= pad);
|
||||
let mut out = ~"\\";
|
||||
unsafe {
|
||||
str::push_str(&mut out, str::from_char(c));
|
||||
for uint::range(str::len(s), pad) |_i|
|
||||
{ str::push_str(&mut out, ~"0"); }
|
||||
str::push_str(&mut out, s);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a 'default' ASCII and C++11-like char-literal escape of a char.
|
||||
*
|
||||
* The default is chosen with a bias toward producing literals that are
|
||||
* legal in a variety of languages, including C++11 and similar C-family
|
||||
* languages. The exact rules are:
|
||||
*
|
||||
* - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
|
||||
* - Single-quote, double-quote and backslash chars are backslash-escaped.
|
||||
* - Any other chars in the range [0x20,0x7e] are not escaped.
|
||||
* - Any other chars are given hex unicode escapes; see `escape_unicode`.
|
||||
*/
|
||||
pub fn escape_default(c: char) -> ~str {
|
||||
match c {
|
||||
'\t' => ~"\\t",
|
||||
'\r' => ~"\\r",
|
||||
'\n' => ~"\\n",
|
||||
'\\' => ~"\\\\",
|
||||
'\'' => ~"\\'",
|
||||
'"' => ~"\\\"",
|
||||
'\x20' .. '\x7e' => str::from_char(c),
|
||||
_ => escape_unicode(c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two chars
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* -1 if a < b, 0 if a == b, +1 if a > b
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn cmp(a: char, b: char) -> int {
|
||||
return if b > a { -1 }
|
||||
else if b < a { 1 }
|
||||
else { 0 }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Eq for char {
|
||||
fn eq(&self, other: &char) -> bool { (*self) == (*other) }
|
||||
fn ne(&self, other: &char) -> bool { (*self) != (*other) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_lowercase() {
|
||||
assert!(is_lowercase('a'));
|
||||
assert!(is_lowercase('ö'));
|
||||
assert!(is_lowercase('ß'));
|
||||
assert!(!is_lowercase('Ü'));
|
||||
assert!(!is_lowercase('P'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_uppercase() {
|
||||
assert!(!is_uppercase('h'));
|
||||
assert!(!is_uppercase('ä'));
|
||||
assert!(!is_uppercase('ß'));
|
||||
assert!(is_uppercase('Ö'));
|
||||
assert!(is_uppercase('T'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_whitespace() {
|
||||
assert!(is_whitespace(' '));
|
||||
assert!(is_whitespace('\u2007'));
|
||||
assert!(is_whitespace('\t'));
|
||||
assert!(is_whitespace('\n'));
|
||||
|
||||
assert!(!is_whitespace('a'));
|
||||
assert!(!is_whitespace('_'));
|
||||
assert!(!is_whitespace('\u0000'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_digit() {
|
||||
assert_eq!(to_digit('0', 10u), Some(0u));
|
||||
assert_eq!(to_digit('1', 2u), Some(1u));
|
||||
assert_eq!(to_digit('2', 3u), Some(2u));
|
||||
assert_eq!(to_digit('9', 10u), Some(9u));
|
||||
assert_eq!(to_digit('a', 16u), Some(10u));
|
||||
assert_eq!(to_digit('A', 16u), Some(10u));
|
||||
assert_eq!(to_digit('b', 16u), Some(11u));
|
||||
assert_eq!(to_digit('B', 16u), Some(11u));
|
||||
assert_eq!(to_digit('z', 36u), Some(35u));
|
||||
assert_eq!(to_digit('Z', 36u), Some(35u));
|
||||
|
||||
assert!(to_digit(' ', 10u).is_none());
|
||||
assert!(to_digit('$', 36u).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_ascii() {
|
||||
assert!(str::all(~"banana", is_ascii));
|
||||
assert!(! str::all(~"ประเทศไทย中华Việt Nam", is_ascii));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_digit() {
|
||||
assert!(is_digit('2'));
|
||||
assert!(is_digit('7'));
|
||||
assert!(! is_digit('c'));
|
||||
assert!(! is_digit('i'));
|
||||
assert!(! is_digit('z'));
|
||||
assert!(! is_digit('Q'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_default() {
|
||||
assert_eq!(escape_default('\n'), ~"\\n");
|
||||
assert_eq!(escape_default('\r'), ~"\\r");
|
||||
assert_eq!(escape_default('\''), ~"\\'");
|
||||
assert_eq!(escape_default('"'), ~"\\\"");
|
||||
assert_eq!(escape_default(' '), ~" ");
|
||||
assert_eq!(escape_default('a'), ~"a");
|
||||
assert_eq!(escape_default('~'), ~"~");
|
||||
assert_eq!(escape_default('\x00'), ~"\\x00");
|
||||
assert_eq!(escape_default('\x1f'), ~"\\x1f");
|
||||
assert_eq!(escape_default('\x7f'), ~"\\x7f");
|
||||
assert_eq!(escape_default('\xff'), ~"\\xff");
|
||||
assert_eq!(escape_default('\u011b'), ~"\\u011b");
|
||||
assert_eq!(escape_default('\U0001d4b6'), ~"\\U0001d4b6");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_escape_unicode() {
|
||||
assert_eq!(escape_unicode('\x00'), ~"\\x00");
|
||||
assert_eq!(escape_unicode('\n'), ~"\\x0a");
|
||||
assert_eq!(escape_unicode(' '), ~"\\x20");
|
||||
assert_eq!(escape_unicode('a'), ~"\\x61");
|
||||
assert_eq!(escape_unicode('\u011b'), ~"\\u011b");
|
||||
assert_eq!(escape_unicode('\U0001d4b6'), ~"\\U0001d4b6");
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[doc(hidden)];
|
||||
|
||||
use libc::{c_char, c_void, intptr_t, uintptr_t};
|
||||
use ptr::mut_null;
|
||||
use repr::BoxRepr;
|
||||
use sys::TypeDesc;
|
||||
use cast::transmute;
|
||||
|
||||
#[cfg(notest)] use ptr::to_unsafe_ptr;
|
||||
|
||||
/**
|
||||
* Runtime structures
|
||||
*
|
||||
* NB: These must match the representation in the C++ runtime.
|
||||
*/
|
||||
|
||||
type DropGlue<'self> = &'self fn(**TypeDesc, *c_void);
|
||||
type FreeGlue<'self> = &'self fn(**TypeDesc, *c_void);
|
||||
|
||||
type TaskID = uintptr_t;
|
||||
|
||||
struct StackSegment { priv opaque: () }
|
||||
struct Scheduler { priv opaque: () }
|
||||
struct SchedulerLoop { priv opaque: () }
|
||||
struct Kernel { priv opaque: () }
|
||||
struct Env { priv opaque: () }
|
||||
struct AllocHeader { priv opaque: () }
|
||||
struct MemoryRegion { priv opaque: () }
|
||||
|
||||
#[cfg(target_arch="x86")]
|
||||
#[cfg(target_arch="arm")]
|
||||
struct Registers {
|
||||
data: [u32, ..16]
|
||||
}
|
||||
|
||||
#[cfg(target_arch="mips")]
|
||||
struct Registers {
|
||||
data: [u32, ..32]
|
||||
}
|
||||
|
||||
#[cfg(target_arch="x86")]
|
||||
#[cfg(target_arch="arm")]
|
||||
#[cfg(target_arch="mips")]
|
||||
struct Context {
|
||||
regs: Registers,
|
||||
next: *Context,
|
||||
pad: [u32, ..3]
|
||||
}
|
||||
|
||||
#[cfg(target_arch="x86_64")]
|
||||
struct Registers {
|
||||
data: [u64, ..22]
|
||||
}
|
||||
|
||||
#[cfg(target_arch="x86_64")]
|
||||
struct Context {
|
||||
regs: Registers,
|
||||
next: *Context,
|
||||
pad: uintptr_t
|
||||
}
|
||||
|
||||
struct BoxedRegion {
|
||||
env: *Env,
|
||||
backing_region: *MemoryRegion,
|
||||
live_allocs: *BoxRepr
|
||||
}
|
||||
|
||||
#[cfg(target_arch="x86")]
|
||||
#[cfg(target_arch="arm")]
|
||||
#[cfg(target_arch="mips")]
|
||||
struct Task {
|
||||
// Public fields
|
||||
refcount: intptr_t, // 0
|
||||
id: TaskID, // 4
|
||||
pad: [u32, ..2], // 8
|
||||
ctx: Context, // 16
|
||||
stack_segment: *StackSegment, // 96
|
||||
runtime_sp: uintptr_t, // 100
|
||||
scheduler: *Scheduler, // 104
|
||||
scheduler_loop: *SchedulerLoop, // 108
|
||||
|
||||
// Fields known only to the runtime
|
||||
kernel: *Kernel, // 112
|
||||
name: *c_char, // 116
|
||||
list_index: i32, // 120
|
||||
boxed_region: BoxedRegion // 128
|
||||
}
|
||||
|
||||
#[cfg(target_arch="x86_64")]
|
||||
struct Task {
|
||||
// Public fields
|
||||
refcount: intptr_t,
|
||||
id: TaskID,
|
||||
ctx: Context,
|
||||
stack_segment: *StackSegment,
|
||||
runtime_sp: uintptr_t,
|
||||
scheduler: *Scheduler,
|
||||
scheduler_loop: *SchedulerLoop,
|
||||
|
||||
// Fields known only to the runtime
|
||||
kernel: *Kernel,
|
||||
name: *c_char,
|
||||
list_index: i32,
|
||||
boxed_region: BoxedRegion
|
||||
}
|
||||
|
||||
/*
|
||||
* Box annihilation
|
||||
*
|
||||
* This runs at task death to free all boxes.
|
||||
*/
|
||||
|
||||
struct AnnihilateStats {
|
||||
n_total_boxes: uint,
|
||||
n_unique_boxes: uint,
|
||||
n_bytes_freed: uint
|
||||
}
|
||||
|
||||
unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) {
|
||||
use managed;
|
||||
|
||||
let task: *Task = transmute(rustrt::rust_get_task());
|
||||
let box = (*task).boxed_region.live_allocs;
|
||||
let mut box: *mut BoxRepr = transmute(copy box);
|
||||
while box != mut_null() {
|
||||
let next = transmute(copy (*box).header.next);
|
||||
let uniq =
|
||||
(*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE;
|
||||
|
||||
if ! f(box, uniq) {
|
||||
break
|
||||
}
|
||||
|
||||
box = next
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn debug_mem() -> bool {
|
||||
::rt::env::get().debug_mem
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn debug_mem() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
|
||||
#[cfg(notest)]
|
||||
#[lang="annihilate"]
|
||||
pub unsafe fn annihilate() {
|
||||
use unstable::lang::local_free;
|
||||
use io::WriterUtil;
|
||||
use io;
|
||||
use libc;
|
||||
use sys;
|
||||
use managed;
|
||||
|
||||
let mut stats = AnnihilateStats {
|
||||
n_total_boxes: 0,
|
||||
n_unique_boxes: 0,
|
||||
n_bytes_freed: 0
|
||||
};
|
||||
|
||||
// Pass 1: Make all boxes immortal.
|
||||
for each_live_alloc |box, uniq| {
|
||||
stats.n_total_boxes += 1;
|
||||
if uniq {
|
||||
stats.n_unique_boxes += 1;
|
||||
} else {
|
||||
(*box).header.ref_count = managed::raw::RC_IMMORTAL;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: Drop all boxes.
|
||||
for each_live_alloc |box, uniq| {
|
||||
if !uniq {
|
||||
let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc);
|
||||
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
|
||||
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 3: Free all boxes.
|
||||
for each_live_alloc |box, uniq| {
|
||||
if !uniq {
|
||||
stats.n_bytes_freed +=
|
||||
(*((*box).header.type_desc)).size
|
||||
+ sys::size_of::<BoxRepr>();
|
||||
local_free(transmute(box));
|
||||
}
|
||||
}
|
||||
|
||||
if debug_mem() {
|
||||
// We do logging here w/o allocation.
|
||||
let dbg = libc::STDERR_FILENO as io::fd_t;
|
||||
dbg.write_str("annihilator stats:");
|
||||
dbg.write_str("\n total_boxes: ");
|
||||
dbg.write_uint(stats.n_total_boxes);
|
||||
dbg.write_str("\n unique_boxes: ");
|
||||
dbg.write_uint(stats.n_unique_boxes);
|
||||
dbg.write_str("\n bytes_freed: ");
|
||||
dbg.write_uint(stats.n_bytes_freed);
|
||||
dbg.write_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/// Bindings to the runtime
|
||||
pub mod rustrt {
|
||||
use libc::c_void;
|
||||
|
||||
#[link_name = "rustrt"]
|
||||
pub extern {
|
||||
#[rust_stack]
|
||||
// FIXME (#4386): Unable to make following method private.
|
||||
pub unsafe fn rust_get_task() -> *c_void;
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*! The Clone trait for types that cannot be "implicitly copied"
|
||||
|
||||
In Rust, some simple types are "implicitly copyable" and when you
|
||||
assign them or pass them as arguments, the receiver will get a copy,
|
||||
leaving the original value in place. These types do not require
|
||||
allocation to copy and do not have finalizers (i.e. they do not
|
||||
contain owned pointers or implement `Drop`), so the compiler considers
|
||||
them cheap and safe to copy and automatically implements the `Copy`
|
||||
trait for them. For other types copies must be made explicitly,
|
||||
by convention implementing the `Clone` trait and calling the
|
||||
`clone` method.
|
||||
|
||||
*/
|
||||
|
||||
pub trait Clone {
|
||||
fn clone(&self) -> Self;
|
||||
}
|
||||
|
||||
impl Clone for () {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> () { () }
|
||||
}
|
||||
|
||||
impl<T:Clone> Clone for ~T {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> ~T { ~(**self).clone() }
|
||||
}
|
||||
|
||||
macro_rules! clone_impl(
|
||||
($t:ty) => {
|
||||
impl Clone for $t {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> $t { *self }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
clone_impl!(int)
|
||||
clone_impl!(i8)
|
||||
clone_impl!(i16)
|
||||
clone_impl!(i32)
|
||||
clone_impl!(i64)
|
||||
|
||||
clone_impl!(uint)
|
||||
clone_impl!(u8)
|
||||
clone_impl!(u16)
|
||||
clone_impl!(u32)
|
||||
clone_impl!(u64)
|
||||
|
||||
clone_impl!(float)
|
||||
clone_impl!(f32)
|
||||
clone_impl!(f64)
|
||||
|
||||
clone_impl!(bool)
|
||||
clone_impl!(char)
|
@ -1,183 +0,0 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
|
||||
The `Ord` and `Eq` comparison traits
|
||||
|
||||
This module contains the definition of both `Ord` and `Eq` which define
|
||||
the common interfaces for doing comparison. Both are language items
|
||||
that the compiler uses to implement the comparison operators. Rust code
|
||||
may implement `Ord` to overload the `<`, `<=`, `>`, and `>=` operators,
|
||||
and `Eq` to overload the `==` and `!=` operators.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Trait for values that can be compared for equality and inequality.
|
||||
*
|
||||
* This trait allows partial equality, where types can be unordered instead of strictly equal or
|
||||
* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both
|
||||
* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11).
|
||||
*
|
||||
* Eventually, this will be implemented by default for types that implement `TotalEq`.
|
||||
*/
|
||||
#[lang="eq"]
|
||||
pub trait Eq {
|
||||
fn eq(&self, other: &Self) -> bool;
|
||||
fn ne(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
/// Trait for equality comparisons where `a == b` and `a != b` are strict inverses.
|
||||
pub trait TotalEq {
|
||||
fn equals(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
macro_rules! totaleq_impl(
|
||||
($t:ty) => {
|
||||
impl TotalEq for $t {
|
||||
#[inline(always)]
|
||||
fn equals(&self, other: &$t) -> bool { *self == *other }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
totaleq_impl!(bool)
|
||||
|
||||
totaleq_impl!(u8)
|
||||
totaleq_impl!(u16)
|
||||
totaleq_impl!(u32)
|
||||
totaleq_impl!(u64)
|
||||
|
||||
totaleq_impl!(i8)
|
||||
totaleq_impl!(i16)
|
||||
totaleq_impl!(i32)
|
||||
totaleq_impl!(i64)
|
||||
|
||||
totaleq_impl!(int)
|
||||
totaleq_impl!(uint)
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Ordering { Less, Equal, Greater }
|
||||
|
||||
/// Trait for types that form a total order
|
||||
pub trait TotalOrd: TotalEq {
|
||||
fn cmp(&self, other: &Self) -> Ordering;
|
||||
}
|
||||
|
||||
macro_rules! totalord_impl(
|
||||
($t:ty) => {
|
||||
impl TotalOrd for $t {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &$t) -> Ordering {
|
||||
if *self < *other { Less }
|
||||
else if *self > *other { Greater }
|
||||
else { Equal }
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
totalord_impl!(u8)
|
||||
totalord_impl!(u16)
|
||||
totalord_impl!(u32)
|
||||
totalord_impl!(u64)
|
||||
|
||||
totalord_impl!(i8)
|
||||
totalord_impl!(i16)
|
||||
totalord_impl!(i32)
|
||||
totalord_impl!(i64)
|
||||
|
||||
totalord_impl!(int)
|
||||
totalord_impl!(uint)
|
||||
|
||||
/**
|
||||
* Trait for values that can be compared for a sort-order.
|
||||
*
|
||||
* Eventually this may be simplified to only require
|
||||
* an `le` method, with the others generated from
|
||||
* default implementations. However it should remain
|
||||
* possible to implement the others separately, for
|
||||
* compatibility with floating-point NaN semantics
|
||||
* (cf. IEEE 754-2008 section 5.11).
|
||||
*/
|
||||
#[lang="ord"]
|
||||
pub trait Ord {
|
||||
fn lt(&self, other: &Self) -> bool;
|
||||
fn le(&self, other: &Self) -> bool;
|
||||
fn ge(&self, other: &Self) -> bool;
|
||||
fn gt(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lt<T:Ord>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).lt(v2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn le<T:Ord>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).le(v2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn eq<T:Eq>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).eq(v2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ne<T:Eq>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).ne(v2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ge<T:Ord>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).ge(v2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn gt<T:Ord>(v1: &T, v2: &T) -> bool {
|
||||
(*v1).gt(v2)
|
||||
}
|
||||
|
||||
/// The equivalence relation. Two values may be equivalent even if they are
|
||||
/// of different types. The most common use case for this relation is
|
||||
/// container types; e.g. it is often desirable to be able to use `&str`
|
||||
/// values to look up entries in a container with `~str` keys.
|
||||
pub trait Equiv<T> {
|
||||
fn equiv(&self, other: &T) -> bool;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn min<T:Ord>(v1: T, v2: T) -> T {
|
||||
if v1 < v2 { v1 } else { v2 }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn max<T:Ord>(v1: T, v2: T) -> T {
|
||||
if v1 > v2 { v1 } else { v2 }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_int_totalord() {
|
||||
assert_eq!(5.cmp(&10), Less);
|
||||
assert_eq!(10.cmp(&5), Greater);
|
||||
assert_eq!(5.cmp(&5), Equal);
|
||||
assert_eq!((-5).cmp(&12), Less);
|
||||
assert_eq!(12.cmp(-5), Greater);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_totaleq() {
|
||||
assert!(5.equals(&5));
|
||||
assert!(!2.equals(&17));
|
||||
}
|
||||
}
|
@ -1,470 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
Message passing
|
||||
*/
|
||||
|
||||
use cast;
|
||||
use either::{Either, Left, Right};
|
||||
use kinds::Owned;
|
||||
use option::{Option, Some, None};
|
||||
use uint;
|
||||
use unstable;
|
||||
use vec;
|
||||
|
||||
use pipes::{recv, try_recv, wait_many, peek, PacketHeader};
|
||||
|
||||
// FIXME #5160: Making this public exposes some plumbing from
|
||||
// pipes. Needs some refactoring
|
||||
pub use pipes::Selectable;
|
||||
|
||||
/// A trait for things that can send multiple messages.
|
||||
pub trait GenericChan<T> {
|
||||
/// Sends a message.
|
||||
fn send(&self, x: T);
|
||||
}
|
||||
|
||||
/// Things that can send multiple messages and can detect when the receiver
|
||||
/// is closed
|
||||
pub trait GenericSmartChan<T> {
|
||||
/// Sends a message, or report if the receiver has closed the connection.
|
||||
fn try_send(&self, x: T) -> bool;
|
||||
}
|
||||
|
||||
/// A trait for things that can receive multiple messages.
|
||||
pub trait GenericPort<T> {
|
||||
/// Receives a message, or fails if the connection closes.
|
||||
fn recv(&self) -> T;
|
||||
|
||||
/** Receives a message, or returns `none` if
|
||||
the connection is closed or closes.
|
||||
*/
|
||||
fn try_recv(&self) -> Option<T>;
|
||||
}
|
||||
|
||||
/// Ports that can `peek`
|
||||
pub trait Peekable<T> {
|
||||
/// Returns true if a message is available
|
||||
fn peek(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Returns the index of an endpoint that is ready to receive.
|
||||
pub fn selecti<T: Selectable>(endpoints: &[T]) -> uint {
|
||||
wait_many(endpoints)
|
||||
}
|
||||
|
||||
/// Returns 0 or 1 depending on which endpoint is ready to receive
|
||||
pub fn select2i<A: Selectable, B: Selectable>(a: &A, b: &B) ->
|
||||
Either<(), ()> {
|
||||
match wait_many([a.header(), b.header()]) {
|
||||
0 => Left(()),
|
||||
1 => Right(()),
|
||||
_ => fail!(~"wait returned unexpected index")
|
||||
}
|
||||
}
|
||||
|
||||
// Streams - Make pipes a little easier in general.
|
||||
|
||||
proto! streamp (
|
||||
Open:send<T: Owned> {
|
||||
data(T) -> Open<T>
|
||||
}
|
||||
)
|
||||
|
||||
#[doc(hidden)]
|
||||
struct Chan_<T> {
|
||||
mut endp: Option<streamp::client::Open<T>>
|
||||
}
|
||||
|
||||
/// An endpoint that can send many messages.
|
||||
pub enum Chan<T> {
|
||||
Chan_(Chan_<T>)
|
||||
}
|
||||
|
||||
struct Port_<T> {
|
||||
mut endp: Option<streamp::server::Open<T>>,
|
||||
}
|
||||
|
||||
/// An endpoint that can receive many messages.
|
||||
pub enum Port<T> {
|
||||
Port_(Port_<T>)
|
||||
}
|
||||
|
||||
/** Creates a `(chan, port)` pair.
|
||||
|
||||
These allow sending or receiving an unlimited number of messages.
|
||||
|
||||
*/
|
||||
pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) {
|
||||
let (c, s) = streamp::init();
|
||||
|
||||
(Port_(Port_ { endp: Some(s) }), Chan_(Chan_{ endp: Some(c) }))
|
||||
}
|
||||
|
||||
// Add an inherent method so that imports of GenericChan are not
|
||||
// required.
|
||||
pub impl<T: Owned> Chan<T> {
|
||||
fn send(&self, x: T) { chan_send(self, x) }
|
||||
fn try_send(&self, x: T) -> bool { chan_try_send(self, x) }
|
||||
}
|
||||
|
||||
impl<T: Owned> GenericChan<T> for Chan<T> {
|
||||
fn send(&self, x: T) { chan_send(self, x) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn chan_send<T:Owned>(self: &Chan<T>, x: T) {
|
||||
let mut endp = None;
|
||||
endp <-> self.endp;
|
||||
self.endp = Some(
|
||||
streamp::client::data(endp.unwrap(), x))
|
||||
}
|
||||
|
||||
impl<T: Owned> GenericSmartChan<T> for Chan<T> {
|
||||
fn try_send(&self, x: T) -> bool {
|
||||
chan_try_send(self, x)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn chan_try_send<T:Owned>(self: &Chan<T>, x: T) -> bool {
|
||||
let mut endp = None;
|
||||
endp <-> self.endp;
|
||||
match streamp::client::try_data(endp.unwrap(), x) {
|
||||
Some(next) => {
|
||||
self.endp = Some(next);
|
||||
true
|
||||
}
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
// Use an inherent impl so that imports are not required:
|
||||
pub impl<T: Owned> Port<T> {
|
||||
fn recv(&self) -> T { port_recv(self) }
|
||||
fn try_recv(&self) -> Option<T> { port_try_recv(self) }
|
||||
fn peek(&self) -> bool { port_peek(self) }
|
||||
}
|
||||
|
||||
impl<T: Owned> GenericPort<T> for Port<T> {
|
||||
// These two calls will prefer the inherent versions above:
|
||||
fn recv(&self) -> T { port_recv(self) }
|
||||
fn try_recv(&self) -> Option<T> { port_try_recv(self) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_recv<T:Owned>(self: &Port<T>) -> T {
|
||||
let mut endp = None;
|
||||
endp <-> self.endp;
|
||||
let streamp::data(x, endp) = recv(endp.unwrap());
|
||||
self.endp = Some(endp);
|
||||
x
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_try_recv<T:Owned>(self: &Port<T>) -> Option<T> {
|
||||
let mut endp = None;
|
||||
endp <-> self.endp;
|
||||
match try_recv(endp.unwrap()) {
|
||||
Some(streamp::data(x, endp)) => {
|
||||
self.endp = Some(endp);
|
||||
Some(x)
|
||||
}
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Owned> Peekable<T> for Port<T> {
|
||||
fn peek(&self) -> bool { port_peek(self) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_peek<T:Owned>(self: &Port<T>) -> bool {
|
||||
unsafe {
|
||||
let mut endp = None;
|
||||
endp <-> self.endp;
|
||||
let peek = match &endp {
|
||||
&Some(ref endp) => peek(endp),
|
||||
&None => fail!(~"peeking empty stream")
|
||||
};
|
||||
self.endp <-> endp;
|
||||
peek
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Owned> Selectable for Port<T> {
|
||||
fn header(&self) -> *PacketHeader {
|
||||
unsafe {
|
||||
match self.endp {
|
||||
Some(ref endp) => endp.header(),
|
||||
None => fail!(~"peeking empty stream")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Treat many ports as one.
|
||||
pub struct PortSet<T> {
|
||||
mut ports: ~[Port<T>],
|
||||
}
|
||||
|
||||
pub fn PortSet<T: Owned>() -> PortSet<T>{
|
||||
PortSet {
|
||||
ports: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
// Use an inherent impl so that imports are not required:
|
||||
pub impl<T:Owned> PortSet<T> {
|
||||
fn recv(&self) -> T { port_set_recv(self) }
|
||||
fn try_recv(&self) -> Option<T> { port_set_try_recv(self) }
|
||||
fn peek(&self) -> bool { port_set_peek(self) }
|
||||
}
|
||||
|
||||
pub impl<T: Owned> PortSet<T> {
|
||||
fn add(&self, port: Port<T>) {
|
||||
self.ports.push(port)
|
||||
}
|
||||
|
||||
fn chan(&self) -> Chan<T> {
|
||||
let (po, ch) = stream();
|
||||
self.add(po);
|
||||
ch
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Owned> GenericPort<T> for PortSet<T> {
|
||||
fn try_recv(&self) -> Option<T> { port_set_try_recv(self) }
|
||||
fn recv(&self) -> T { port_set_recv(self) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_set_recv<T:Owned>(self: &PortSet<T>) -> T {
|
||||
port_set_try_recv(self).expect("port_set: endpoints closed")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_set_try_recv<T:Owned>(self: &PortSet<T>) -> Option<T> {
|
||||
let mut result = None;
|
||||
// we have to swap the ports array so we aren't borrowing
|
||||
// aliasable mutable memory.
|
||||
let mut ports = ~[];
|
||||
ports <-> self.ports;
|
||||
while result.is_none() && ports.len() > 0 {
|
||||
let i = wait_many(ports);
|
||||
match ports[i].try_recv() {
|
||||
Some(m) => {
|
||||
result = Some(m);
|
||||
}
|
||||
None => {
|
||||
// Remove this port.
|
||||
let _ = ports.swap_remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ports <-> self.ports;
|
||||
result
|
||||
}
|
||||
|
||||
impl<T: Owned> Peekable<T> for PortSet<T> {
|
||||
fn peek(&self) -> bool { port_set_peek(self) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn port_set_peek<T:Owned>(self: &PortSet<T>) -> bool {
|
||||
// It'd be nice to use self.port.each, but that version isn't
|
||||
// pure.
|
||||
for uint::range(0, vec::uniq_len(&const self.ports)) |i| {
|
||||
// XXX: Botch pending demuting.
|
||||
unsafe {
|
||||
let port: &Port<T> = cast::transmute(&mut self.ports[i]);
|
||||
if port.peek() { return true }
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
/// A channel that can be shared between many senders.
|
||||
pub type SharedChan<T> = unstable::Exclusive<Chan<T>>;
|
||||
|
||||
pub impl<T: Owned> SharedChan<T> {
|
||||
fn send(&self, x: T) { shared_chan_send(self, x) }
|
||||
fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) }
|
||||
}
|
||||
|
||||
impl<T: Owned> GenericChan<T> for SharedChan<T> {
|
||||
fn send(&self, x: T) { shared_chan_send(self, x) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn shared_chan_send<T:Owned>(self: &SharedChan<T>, x: T) {
|
||||
let mut xx = Some(x);
|
||||
do self.with_imm |chan| {
|
||||
let mut x = None;
|
||||
x <-> xx;
|
||||
chan.send(x.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Owned> GenericSmartChan<T> for SharedChan<T> {
|
||||
fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn shared_chan_try_send<T:Owned>(self: &SharedChan<T>, x: T) -> bool {
|
||||
let mut xx = Some(x);
|
||||
do self.with_imm |chan| {
|
||||
let mut x = None;
|
||||
x <-> xx;
|
||||
chan.try_send(x.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `chan` into a `shared_chan`.
|
||||
pub fn SharedChan<T:Owned>(c: Chan<T>) -> SharedChan<T> {
|
||||
unstable::exclusive(c)
|
||||
}
|
||||
|
||||
/// Receive a message from one of two endpoints.
|
||||
pub trait Select2<T: Owned, U: Owned> {
|
||||
/// Receive a message or return `None` if a connection closes.
|
||||
fn try_select(&self) -> Either<Option<T>, Option<U>>;
|
||||
/// Receive a message or fail if a connection closes.
|
||||
fn select(&self) -> Either<T, U>;
|
||||
}
|
||||
|
||||
impl<T: Owned, U: Owned,
|
||||
Left: Selectable + GenericPort<T>,
|
||||
Right: Selectable + GenericPort<U>>
|
||||
Select2<T, U> for (Left, Right) {
|
||||
|
||||
fn select(&self) -> Either<T, U> {
|
||||
match *self {
|
||||
(ref lp, ref rp) => match select2i(lp, rp) {
|
||||
Left(()) => Left (lp.recv()),
|
||||
Right(()) => Right(rp.recv())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_select(&self) -> Either<Option<T>, Option<U>> {
|
||||
match *self {
|
||||
(ref lp, ref rp) => match select2i(lp, rp) {
|
||||
Left(()) => Left (lp.try_recv()),
|
||||
Right(()) => Right(rp.try_recv())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proto! oneshot (
|
||||
Oneshot:send<T:Owned> {
|
||||
send(T) -> !
|
||||
}
|
||||
)
|
||||
|
||||
/// The send end of a oneshot pipe.
|
||||
pub type ChanOne<T> = oneshot::client::Oneshot<T>;
|
||||
/// The receive end of a oneshot pipe.
|
||||
pub type PortOne<T> = oneshot::server::Oneshot<T>;
|
||||
|
||||
/// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair.
|
||||
pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) {
|
||||
let (chan, port) = oneshot::init();
|
||||
(port, chan)
|
||||
}
|
||||
|
||||
pub impl<T: Owned> PortOne<T> {
|
||||
fn recv(self) -> T { recv_one(self) }
|
||||
fn try_recv(self) -> Option<T> { try_recv_one(self) }
|
||||
}
|
||||
|
||||
pub impl<T: Owned> ChanOne<T> {
|
||||
fn send(self, data: T) { send_one(self, data) }
|
||||
fn try_send(self, data: T) -> bool { try_send_one(self, data) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a message from a oneshot pipe, failing if the connection was
|
||||
* closed.
|
||||
*/
|
||||
pub fn recv_one<T: Owned>(port: PortOne<T>) -> T {
|
||||
let oneshot::send(message) = recv(port);
|
||||
message
|
||||
}
|
||||
|
||||
/// Receive a message from a oneshot pipe unless the connection was closed.
|
||||
pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> {
|
||||
let message = try_recv(port);
|
||||
|
||||
if message.is_none() { None }
|
||||
else {
|
||||
let oneshot::send(message) = message.unwrap();
|
||||
Some(message)
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a message on a oneshot pipe, failing if the connection was closed.
|
||||
pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) {
|
||||
oneshot::client::send(chan, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message on a oneshot pipe, or return false if the connection was
|
||||
* closed.
|
||||
*/
|
||||
pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T)
|
||||
-> bool {
|
||||
oneshot::client::try_send(chan, data).is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use either::Right;
|
||||
use super::{Chan, Port, oneshot, recv_one, stream};
|
||||
|
||||
#[test]
|
||||
pub fn test_select2() {
|
||||
let (p1, c1) = stream();
|
||||
let (p2, c2) = stream();
|
||||
|
||||
c1.send(~"abc");
|
||||
|
||||
match (p1, p2).select() {
|
||||
Right(_) => fail!(),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
c2.send(123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_oneshot() {
|
||||
let (c, p) = oneshot::init();
|
||||
|
||||
oneshot::client::send(c, ());
|
||||
|
||||
recv_one(p)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peek_terminated() {
|
||||
let (port, chan): (Port<int>, Chan<int>) = stream();
|
||||
|
||||
{
|
||||
// Destroy the channel
|
||||
let _chan = chan;
|
||||
}
|
||||
|
||||
assert!(!port.peek());
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Container traits
|
||||
|
||||
use option::Option;
|
||||
|
||||
pub trait Container {
|
||||
/// Return the number of elements in the container
|
||||
fn len(&const self) -> uint;
|
||||
|
||||
/// Return true if the container contains no elements
|
||||
fn is_empty(&const self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Mutable: Container {
|
||||
/// Clear the container, removing all values.
|
||||
fn clear(&mut self);
|
||||
}
|
||||
|
||||
pub trait Map<K, V>: Mutable {
|
||||
/// Return true if the map contains a value for the specified key
|
||||
fn contains_key(&self, key: &K) -> bool;
|
||||
|
||||
/// Visit all keys
|
||||
fn each_key(&self, f: &fn(&K) -> bool);
|
||||
|
||||
/// Visit all values
|
||||
fn each_value(&self, f: &fn(&V) -> bool);
|
||||
|
||||
/// Iterate over the map and mutate the contained values
|
||||
fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool);
|
||||
|
||||
/// Return a reference to the value corresponding to the key
|
||||
fn find(&self, key: &K) -> Option<&'self V>;
|
||||
|
||||
/// Return a mutable reference to the value corresponding to the key
|
||||
fn find_mut(&mut self, key: &K) -> Option<&'self mut V>;
|
||||
|
||||
/// Insert a key-value pair into the map. An existing value for a
|
||||
/// key is replaced by the new value. Return true if the key did
|
||||
/// not already exist in the map.
|
||||
fn insert(&mut self, key: K, value: V) -> bool;
|
||||
|
||||
/// Remove a key-value pair from the map. Return true if the key
|
||||
/// was present in the map, otherwise false.
|
||||
fn remove(&mut self, key: &K) -> bool;
|
||||
}
|
||||
|
||||
pub trait Set<T>: Mutable {
|
||||
/// Return true if the set contains a value
|
||||
fn contains(&self, value: &T) -> bool;
|
||||
|
||||
/// Add a value to the set. Return true if the value was not already
|
||||
/// present in the set.
|
||||
fn insert(&mut self, value: T) -> bool;
|
||||
|
||||
/// Remove a value from the set. Return true if the value was
|
||||
/// present in the set.
|
||||
fn remove(&mut self, value: &T) -> bool;
|
||||
|
||||
/// Return true if the set has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
fn is_disjoint(&self, other: &Self) -> bool;
|
||||
|
||||
/// Return true if the set is a subset of another
|
||||
fn is_subset(&self, other: &Self) -> bool;
|
||||
|
||||
/// Return true if the set is a superset of another
|
||||
fn is_superset(&self, other: &Self) -> bool;
|
||||
|
||||
/// Visit the values representing the difference
|
||||
fn difference(&self, other: &Self, f: &fn(&T) -> bool);
|
||||
|
||||
/// Visit the values representing the symmetric difference
|
||||
fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool);
|
||||
|
||||
/// Visit the values representing the intersection
|
||||
fn intersection(&self, other: &Self, f: &fn(&T) -> bool);
|
||||
|
||||
/// Visit the values representing the union
|
||||
fn union(&self, other: &Self, f: &fn(&T) -> bool);
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
|
||||
# The Rust core library
|
||||
|
||||
The Rust core library provides runtime features required by the language,
|
||||
including the task scheduler and memory allocators, as well as library
|
||||
support for Rust built-in types, platform abstractions, and other commonly
|
||||
used features.
|
||||
|
||||
`core` includes modules corresponding to each of the integer types, each of
|
||||
the floating point types, the `bool` type, tuples, characters, strings
|
||||
(`str`), vectors (`vec`), managed boxes (`managed`), owned boxes (`owned`),
|
||||
and unsafe and borrowed pointers (`ptr`). Additionally, `core` provides
|
||||
pervasive types (`option` and `result`), task creation and communication
|
||||
primitives (`task`, `comm`), platform abstractions (`os` and `path`), basic
|
||||
I/O abstractions (`io`), common traits (`kinds`, `ops`, `cmp`, `num`,
|
||||
`to_str`), and complete bindings to the C standard library (`libc`).
|
||||
|
||||
# Core injection and the Rust prelude
|
||||
|
||||
`core` is imported at the topmost level of every crate by default, as
|
||||
if the first line of each crate was
|
||||
|
||||
extern mod core;
|
||||
|
||||
This means that the contents of core can be accessed from from any context
|
||||
with the `core::` path prefix, as in `use core::vec`, `use core::task::spawn`,
|
||||
etc.
|
||||
|
||||
Additionally, `core` contains a `prelude` module that reexports many of the
|
||||
most common core modules, types and traits. The contents of the prelude are
|
||||
imported into every *module* by default. Implicitly, all modules behave as if
|
||||
they contained the following prologue:
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#[link(name = "core",
|
||||
vers = "0.6",
|
||||
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/libcore")];
|
||||
|
||||
#[comment = "The Rust core library"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
|
||||
// Don't link to core. We are core.
|
||||
#[no_core];
|
||||
|
||||
#[warn(vecs_implicitly_copyable)];
|
||||
#[deny(non_camel_case_types)];
|
||||
#[allow(deprecated_mutable_fields)];
|
||||
#[allow(deprecated_drop)];
|
||||
|
||||
// Make core testable by not duplicating lang items. See #2912
|
||||
#[cfg(test)] extern mod realcore(name = "core", vers = "0.6");
|
||||
#[cfg(test)] pub use kinds = realcore::kinds;
|
||||
#[cfg(test)] pub use ops = realcore::ops;
|
||||
#[cfg(test)] pub use cmp = realcore::cmp;
|
||||
|
||||
/* Reexported core operators */
|
||||
|
||||
pub use kinds::{Const, Copy, Owned, Durable};
|
||||
pub use ops::{Drop};
|
||||
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not};
|
||||
pub use ops::{BitAnd, BitOr, BitXor};
|
||||
pub use ops::{Shl, Shr, Index};
|
||||
|
||||
|
||||
/* Reexported types and traits */
|
||||
|
||||
pub use option::{Option, Some, None};
|
||||
pub use result::{Result, Ok, Err};
|
||||
|
||||
pub use path::Path;
|
||||
pub use path::GenericPath;
|
||||
pub use path::WindowsPath;
|
||||
pub use path::PosixPath;
|
||||
|
||||
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
||||
pub use str::{StrSlice};
|
||||
pub use container::{Container, Mutable};
|
||||
pub use vec::{CopyableVector, ImmutableVector};
|
||||
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
|
||||
pub use vec::{OwnedVector, OwnedCopyableVector};
|
||||
pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
|
||||
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
|
||||
|
||||
pub use num::NumCast;
|
||||
pub use ptr::Ptr;
|
||||
pub use to_str::ToStr;
|
||||
pub use clone::Clone;
|
||||
|
||||
// On Linux, link to the runtime with -lrt.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[doc(hidden)]
|
||||
pub mod linkhack {
|
||||
#[link_args="-lrustrt -lrt"]
|
||||
#[link_args = "-lpthread"]
|
||||
extern {
|
||||
}
|
||||
}
|
||||
|
||||
/* The Prelude. */
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
/* Primitive types */
|
||||
|
||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/int.rs"]
|
||||
pub mod int;
|
||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i8.rs"]
|
||||
pub mod i8;
|
||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i16.rs"]
|
||||
pub mod i16;
|
||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i32.rs"]
|
||||
pub mod i32;
|
||||
#[path = "num/int-template.rs"] #[merge = "num/int-template/i64.rs"]
|
||||
pub mod i64;
|
||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/uint.rs"]
|
||||
pub mod uint;
|
||||
|
||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u8.rs"]
|
||||
pub mod u8;
|
||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u16.rs"]
|
||||
pub mod u16;
|
||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u32.rs"]
|
||||
pub mod u32;
|
||||
#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u64.rs"]
|
||||
pub mod u64;
|
||||
|
||||
#[path = "num/float.rs"]
|
||||
pub mod float;
|
||||
#[path = "num/f32.rs"]
|
||||
pub mod f32;
|
||||
#[path = "num/f64.rs"]
|
||||
pub mod f64;
|
||||
|
||||
pub mod nil;
|
||||
pub mod bool;
|
||||
pub mod char;
|
||||
pub mod tuple;
|
||||
|
||||
pub mod vec;
|
||||
pub mod at_vec;
|
||||
pub mod str;
|
||||
|
||||
pub mod ptr;
|
||||
pub mod owned;
|
||||
pub mod managed;
|
||||
|
||||
|
||||
/* Core language traits */
|
||||
|
||||
#[cfg(notest)] pub mod kinds;
|
||||
#[cfg(notest)] pub mod ops;
|
||||
#[cfg(notest)] pub mod cmp;
|
||||
|
||||
|
||||
/* Common traits */
|
||||
|
||||
pub mod from_str;
|
||||
#[path = "num/num.rs"]
|
||||
pub mod num;
|
||||
pub mod iter;
|
||||
pub mod to_str;
|
||||
pub mod to_bytes;
|
||||
pub mod clone;
|
||||
pub mod io;
|
||||
pub mod hash;
|
||||
pub mod container;
|
||||
|
||||
|
||||
/* Common data structures */
|
||||
|
||||
pub mod option;
|
||||
pub mod result;
|
||||
pub mod either;
|
||||
pub mod hashmap;
|
||||
pub mod cell;
|
||||
pub mod trie;
|
||||
|
||||
|
||||
/* Tasks and communication */
|
||||
|
||||
#[path = "task/mod.rs"]
|
||||
pub mod task;
|
||||
pub mod comm;
|
||||
pub mod pipes;
|
||||
|
||||
|
||||
/* Runtime and platform support */
|
||||
|
||||
pub mod gc;
|
||||
pub mod libc;
|
||||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod rand;
|
||||
pub mod run;
|
||||
pub mod sys;
|
||||
pub mod cast;
|
||||
pub mod mutable;
|
||||
pub mod flate;
|
||||
pub mod repr;
|
||||
pub mod cleanup;
|
||||
pub mod reflect;
|
||||
pub mod condition;
|
||||
pub mod logging;
|
||||
pub mod util;
|
||||
|
||||
|
||||
/* Unsupported interfaces */
|
||||
|
||||
// Private APIs
|
||||
pub mod unstable;
|
||||
|
||||
/* For internal use, not exported */
|
||||
|
||||
pub mod unicode;
|
||||
#[path = "num/cmath.rs"]
|
||||
pub mod cmath;
|
||||
pub mod stackwalk;
|
||||
#[path = "rt/mod.rs"]
|
||||
pub mod rt;
|
||||
|
||||
// A curious inner-module that's not exported that contains the binding
|
||||
// 'core' so that macro-expanded references to core::error and such
|
||||
// can be resolved within libcore.
|
||||
#[doc(hidden)]
|
||||
mod core {
|
||||
pub use clone;
|
||||
pub use cmp;
|
||||
pub use condition;
|
||||
pub use option;
|
||||
pub use kinds;
|
||||
pub use sys;
|
||||
pub use pipes;
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
@ -1,275 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A type that represents one of two alternatives
|
||||
|
||||
use cmp::Eq;
|
||||
use kinds::Copy;
|
||||
use result::Result;
|
||||
use result;
|
||||
use vec;
|
||||
|
||||
/// The either type
|
||||
#[deriving(Clone, Eq)]
|
||||
pub enum Either<T, U> {
|
||||
Left(T),
|
||||
Right(U)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn either<T, U, V>(f_left: &fn(&T) -> V,
|
||||
f_right: &fn(&U) -> V, value: &Either<T, U>) -> V {
|
||||
/*!
|
||||
* Applies a function based on the given either value
|
||||
*
|
||||
* If `value` is left(T) then `f_left` is applied to its contents, if
|
||||
* `value` is right(U) then `f_right` is applied to its contents, and the
|
||||
* result is returned.
|
||||
*/
|
||||
|
||||
match *value {
|
||||
Left(ref l) => f_left(l),
|
||||
Right(ref r) => f_right(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lefts<T:Copy,U>(eithers: &[Either<T, U>]) -> ~[T] {
|
||||
//! Extracts from a vector of either all the left values
|
||||
|
||||
do vec::build_sized(eithers.len()) |push| {
|
||||
for vec::each(eithers) |elt| {
|
||||
match *elt {
|
||||
Left(ref l) => { push(*l); }
|
||||
_ => { /* fallthrough */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] {
|
||||
//! Extracts from a vector of either all the right values
|
||||
|
||||
do vec::build_sized(eithers.len()) |push| {
|
||||
for vec::each(eithers) |elt| {
|
||||
match *elt {
|
||||
Right(ref r) => { push(*r); }
|
||||
_ => { /* fallthrough */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn partition<T, U>(eithers: ~[Either<T, U>])
|
||||
-> (~[T], ~[U]) {
|
||||
/*!
|
||||
* Extracts from a vector of either all the left values and right values
|
||||
*
|
||||
* Returns a structure containing a vector of left values and a vector of
|
||||
* right values.
|
||||
*/
|
||||
|
||||
let mut lefts: ~[T] = ~[];
|
||||
let mut rights: ~[U] = ~[];
|
||||
do vec::consume(eithers) |_i, elt| {
|
||||
match elt {
|
||||
Left(l) => lefts.push(l),
|
||||
Right(r) => rights.push(r)
|
||||
}
|
||||
}
|
||||
return (lefts, rights);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flip<T, U>(eith: Either<T, U>) -> Either<U, T> {
|
||||
//! Flips between left and right of a given either
|
||||
|
||||
match eith {
|
||||
Right(r) => Left(r),
|
||||
Left(l) => Right(l)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_result<T, U>(eith: Either<T, U>)
|
||||
-> Result<U, T> {
|
||||
/*!
|
||||
* Converts either::t to a result::t
|
||||
*
|
||||
* Converts an `either` type to a `result` type, making the "right" choice
|
||||
* an ok result, and the "left" choice a fail
|
||||
*/
|
||||
|
||||
match eith {
|
||||
Right(r) => result::Ok(r),
|
||||
Left(l) => result::Err(l)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_left<T, U>(eith: &Either<T, U>) -> bool {
|
||||
//! Checks whether the given value is a left
|
||||
|
||||
match *eith { Left(_) => true, _ => false }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_right<T, U>(eith: &Either<T, U>) -> bool {
|
||||
//! Checks whether the given value is a right
|
||||
|
||||
match *eith { Right(_) => true, _ => false }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T {
|
||||
//! Retrieves the value in the left branch. Fails if the either is Right.
|
||||
|
||||
match eith {
|
||||
Left(x) => x,
|
||||
Right(_) => fail!(~"either::unwrap_left Right")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U {
|
||||
//! Retrieves the value in the right branch. Fails if the either is Left.
|
||||
|
||||
match eith {
|
||||
Right(x) => x,
|
||||
Left(_) => fail!(~"either::unwrap_right Left")
|
||||
}
|
||||
}
|
||||
|
||||
pub impl<T, U> Either<T, U> {
|
||||
#[inline(always)]
|
||||
fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V {
|
||||
either(f_left, f_right, self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn flip(self) -> Either<U, T> { flip(self) }
|
||||
|
||||
#[inline(always)]
|
||||
fn to_result(self) -> Result<U, T> { to_result(self) }
|
||||
|
||||
#[inline(always)]
|
||||
fn is_left(&self) -> bool { is_left(self) }
|
||||
|
||||
#[inline(always)]
|
||||
fn is_right(&self) -> bool { is_right(self) }
|
||||
|
||||
#[inline(always)]
|
||||
fn unwrap_left(self) -> T { unwrap_left(self) }
|
||||
|
||||
#[inline(always)]
|
||||
fn unwrap_right(self) -> U { unwrap_right(self) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_either_left() {
|
||||
let val = Left(10);
|
||||
fn f_left(x: &int) -> bool { *x == 10 }
|
||||
fn f_right(_x: &uint) -> bool { false }
|
||||
assert!((either(f_left, f_right, &val)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_either_right() {
|
||||
let val = Right(10u);
|
||||
fn f_left(_x: &int) -> bool { false }
|
||||
fn f_right(x: &uint) -> bool { *x == 10u }
|
||||
assert!((either(f_left, f_right, &val)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lefts() {
|
||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
||||
let result = lefts(input);
|
||||
assert_eq!(result, ~[10, 12, 14]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lefts_none() {
|
||||
let input: ~[Either<int, int>] = ~[Right(10), Right(10)];
|
||||
let result = lefts(input);
|
||||
assert_eq!(vec::len(result), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lefts_empty() {
|
||||
let input: ~[Either<int, int>] = ~[];
|
||||
let result = lefts(input);
|
||||
assert_eq!(vec::len(result), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rights() {
|
||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
||||
let result = rights(input);
|
||||
assert_eq!(result, ~[11, 13]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rights_none() {
|
||||
let input: ~[Either<int, int>] = ~[Left(10), Left(10)];
|
||||
let result = rights(input);
|
||||
assert_eq!(vec::len(result), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rights_empty() {
|
||||
let input: ~[Either<int, int>] = ~[];
|
||||
let result = rights(input);
|
||||
assert_eq!(vec::len(result), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partition() {
|
||||
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
||||
let (lefts, rights) = partition(input);
|
||||
assert_eq!(lefts[0], 10);
|
||||
assert_eq!(lefts[1], 12);
|
||||
assert_eq!(lefts[2], 14);
|
||||
assert_eq!(rights[0], 11);
|
||||
assert_eq!(rights[1], 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partition_no_lefts() {
|
||||
let input: ~[Either<int, int>] = ~[Right(10), Right(11)];
|
||||
let (lefts, rights) = partition(input);
|
||||
assert_eq!(vec::len(lefts), 0u);
|
||||
assert_eq!(vec::len(rights), 2u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partition_no_rights() {
|
||||
let input: ~[Either<int, int>] = ~[Left(10), Left(11)];
|
||||
let (lefts, rights) = partition(input);
|
||||
assert_eq!(vec::len(lefts), 2u);
|
||||
assert_eq!(vec::len(rights), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partition_empty() {
|
||||
let input: ~[Either<int, int>] = ~[];
|
||||
let (lefts, rights) = partition(input);
|
||||
assert_eq!(vec::len(lefts), 0u);
|
||||
assert_eq!(vec::len(rights), 0u);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
@ -1,107 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
|
||||
Simple compression
|
||||
|
||||
*/
|
||||
|
||||
use libc;
|
||||
use libc::{c_void, size_t, c_int};
|
||||
use ptr;
|
||||
use vec;
|
||||
|
||||
#[cfg(test)] use rand;
|
||||
#[cfg(test)] use rand::RngUtil;
|
||||
|
||||
pub mod rustrt {
|
||||
use libc::{c_int, c_void, size_t};
|
||||
|
||||
#[link_name = "rustrt"]
|
||||
pub extern {
|
||||
unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
|
||||
src_buf_len: size_t,
|
||||
pout_len: *size_t,
|
||||
flags: c_int)
|
||||
-> *c_void;
|
||||
|
||||
unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
|
||||
src_buf_len: size_t,
|
||||
pout_len: *size_t,
|
||||
flags: c_int)
|
||||
-> *c_void;
|
||||
}
|
||||
}
|
||||
|
||||
static lz_none : c_int = 0x0; // Huffman-coding only.
|
||||
static lz_fast : c_int = 0x1; // LZ with only one probe
|
||||
static lz_norm : c_int = 0x80; // LZ with 128 probes, "normal"
|
||||
static lz_best : c_int = 0xfff; // LZ with 4095 probes, "best"
|
||||
|
||||
pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] {
|
||||
do vec::as_const_buf(bytes) |b, len| {
|
||||
unsafe {
|
||||
let mut outsz : size_t = 0;
|
||||
let res =
|
||||
rustrt::tdefl_compress_mem_to_heap(b as *c_void,
|
||||
len as size_t,
|
||||
ptr::addr_of(&outsz),
|
||||
lz_norm);
|
||||
assert!(res as int != 0);
|
||||
let out = vec::raw::from_buf_raw(res as *u8,
|
||||
outsz as uint);
|
||||
libc::free(res);
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] {
|
||||
do vec::as_const_buf(bytes) |b, len| {
|
||||
unsafe {
|
||||
let mut outsz : size_t = 0;
|
||||
let res =
|
||||
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
|
||||
len as size_t,
|
||||
ptr::addr_of(&outsz),
|
||||
0);
|
||||
assert!(res as int != 0);
|
||||
let out = vec::raw::from_buf_raw(res as *u8,
|
||||
outsz as uint);
|
||||
libc::free(res);
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
fn test_flate_round_trip() {
|
||||
let r = rand::Rng();
|
||||
let mut words = ~[];
|
||||
for 20.times {
|
||||
words.push(r.gen_bytes(r.gen_uint_range(1, 10)));
|
||||
}
|
||||
for 20.times {
|
||||
let mut in = ~[];
|
||||
for 2000.times {
|
||||
in.push_all(r.choose(words));
|
||||
}
|
||||
debug!("de/inflate of %u bytes of random word-sequences",
|
||||
in.len());
|
||||
let cmp = deflate_bytes(in);
|
||||
let out = inflate_bytes(cmp);
|
||||
debug!("%u bytes deflated to %u (%.1f%% size)",
|
||||
in.len(), cmp.len(),
|
||||
100.0 * ((cmp.len() as float) / (in.len() as float)));
|
||||
assert!((in == out));
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The trait for types that can be created from strings
|
||||
|
||||
use option::Option;
|
||||
|
||||
pub trait FromStr {
|
||||
fn from_str(s: &str) -> Option<Self>;
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[doc(hidden)];
|
||||
|
||||
/*! Precise garbage collector
|
||||
|
||||
The precise GC exposes two functions, gc and
|
||||
cleanup_stack_for_failure. The gc function is the entry point to the
|
||||
garbage collector itself. The cleanup_stack_for_failure is the entry
|
||||
point for GC-based cleanup.
|
||||
|
||||
Precise GC depends on changes to LLVM's GC which add support for
|
||||
automatic rooting and addrspace-based metadata marking. Rather than
|
||||
explicitly rooting pointers with LLVM's gcroot intrinsic, the GC
|
||||
merely creates allocas for pointers, and allows an LLVM pass to
|
||||
automatically infer roots based on the allocas present in a function
|
||||
(and live at a given location). The compiler communicates the type of
|
||||
the pointer to LLVM by setting the addrspace of the pointer type. The
|
||||
compiler then emits a map from addrspace to tydesc, which LLVM then
|
||||
uses to match pointers with their tydesc. The GC reads the metadata
|
||||
table produced by LLVM, and uses it to determine which glue functions
|
||||
to call to free objects on their respective heaps.
|
||||
|
||||
GC-based cleanup is a replacement for landing pads which relies on the
|
||||
GC infrastructure to find pointers on the stack to cleanup. Whereas
|
||||
the normal GC needs to walk task-local heap allocations, the cleanup
|
||||
code needs to walk exchange heap allocations and stack-allocations
|
||||
with destructors.
|
||||
|
||||
*/
|
||||
|
||||
use cast;
|
||||
use container::{Map, Set};
|
||||
use io;
|
||||
use libc::{size_t, uintptr_t};
|
||||
use option::{None, Option, Some};
|
||||
use ptr;
|
||||
use hashmap::linear::LinearSet;
|
||||
use stackwalk;
|
||||
use sys;
|
||||
|
||||
pub use stackwalk::Word;
|
||||
|
||||
// Mirrors rust_stack.h stk_seg
|
||||
pub struct StackSegment {
|
||||
prev: *StackSegment,
|
||||
next: *StackSegment,
|
||||
end: uintptr_t,
|
||||
// And other fields which we don't care about...
|
||||
}
|
||||
|
||||
pub mod rustrt {
|
||||
use libc::size_t;
|
||||
use stackwalk::Word;
|
||||
use super::StackSegment;
|
||||
|
||||
#[link_name = "rustrt"]
|
||||
pub extern {
|
||||
#[rust_stack]
|
||||
pub unsafe fn rust_call_tydesc_glue(root: *Word,
|
||||
tydesc: *Word,
|
||||
field: size_t);
|
||||
|
||||
#[rust_stack]
|
||||
pub unsafe fn rust_gc_metadata() -> *Word;
|
||||
|
||||
pub unsafe fn rust_get_stack_segment() -> *StackSegment;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U {
|
||||
return cast::reinterpret_cast(&ptr::offset(ptr, count));
|
||||
}
|
||||
|
||||
unsafe fn align_to_pointer<T>(ptr: *T) -> *T {
|
||||
let align = sys::min_align_of::<*T>();
|
||||
let ptr: uint = cast::reinterpret_cast(&ptr);
|
||||
let ptr = (ptr + (align - 1)) & -align;
|
||||
return cast::reinterpret_cast(&ptr);
|
||||
}
|
||||
|
||||
unsafe fn get_safe_point_count() -> uint {
|
||||
let module_meta = rustrt::rust_gc_metadata();
|
||||
return *module_meta;
|
||||
}
|
||||
|
||||
struct SafePoint {
|
||||
sp_meta: *Word,
|
||||
fn_meta: *Word,
|
||||
}
|
||||
|
||||
// Returns the safe point metadata for the given program counter, if
|
||||
// any.
|
||||
unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
|
||||
let module_meta = rustrt::rust_gc_metadata();
|
||||
let num_safe_points = *module_meta;
|
||||
let safe_points: *Word = bump(module_meta, 1);
|
||||
|
||||
if ptr::is_null(pc) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// FIXME (#2997): Use binary rather than linear search.
|
||||
let mut spi = 0;
|
||||
while spi < num_safe_points {
|
||||
let sp: **Word = bump(safe_points, spi*3);
|
||||
let sp_loc = *sp;
|
||||
if sp_loc == pc {
|
||||
return Some(SafePoint {
|
||||
sp_meta: *bump(sp, 1),
|
||||
fn_meta: *bump(sp, 2),
|
||||
});
|
||||
}
|
||||
spi += 1;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
type Visitor<'self> = &'self fn(root: **Word, tydesc: *Word) -> bool;
|
||||
|
||||
// Walks the list of roots for the given safe point, and calls visitor
|
||||
// on each root.
|
||||
unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
|
||||
let fp_bytes: *u8 = cast::reinterpret_cast(&fp);
|
||||
let sp_meta: *u32 = cast::reinterpret_cast(&sp.sp_meta);
|
||||
|
||||
let num_stack_roots = *sp_meta as uint;
|
||||
let num_reg_roots = *ptr::offset(sp_meta, 1) as uint;
|
||||
|
||||
let stack_roots: *u32 = bump(sp_meta, 2);
|
||||
let reg_roots: *u8 = bump(stack_roots, num_stack_roots);
|
||||
let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots));
|
||||
let tydescs: ***Word = bump(addrspaces, num_stack_roots);
|
||||
|
||||
// Stack roots
|
||||
let mut sri = 0;
|
||||
while sri < num_stack_roots {
|
||||
if *ptr::offset(addrspaces, sri) >= 1 {
|
||||
let root =
|
||||
ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word)
|
||||
as **Word;
|
||||
let tydescpp = ptr::offset(tydescs, sri);
|
||||
let tydesc = if ptr::is_not_null(tydescpp) &&
|
||||
ptr::is_not_null(*tydescpp) {
|
||||
**tydescpp
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
if !visitor(root, tydesc) { return; }
|
||||
}
|
||||
sri += 1;
|
||||
}
|
||||
|
||||
// Register roots
|
||||
let mut rri = 0;
|
||||
while rri < num_reg_roots {
|
||||
if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 {
|
||||
// FIXME(#2997): Need to find callee saved registers on the stack.
|
||||
}
|
||||
rri += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Is fp contained in segment?
|
||||
unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool {
|
||||
let begin: Word = cast::reinterpret_cast(&segment);
|
||||
let end: Word = cast::reinterpret_cast(&(*segment).end);
|
||||
let frame: Word = cast::reinterpret_cast(&fp);
|
||||
|
||||
return begin <= frame && frame <= end;
|
||||
}
|
||||
|
||||
struct Segment { segment: *StackSegment, boundary: bool }
|
||||
|
||||
// Find and return the segment containing the given frame pointer. At
|
||||
// stack segment boundaries, returns true for boundary, so that the
|
||||
// caller can do any special handling to identify where the correct
|
||||
// return address is in the stack frame.
|
||||
unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment)
|
||||
-> Segment {
|
||||
// Check if frame is in either current frame or previous frame.
|
||||
let in_segment = is_frame_in_segment(fp, segment);
|
||||
let in_prev_segment = ptr::is_not_null((*segment).prev) &&
|
||||
is_frame_in_segment(fp, (*segment).prev);
|
||||
|
||||
// If frame is not in either segment, walk down segment list until
|
||||
// we find the segment containing this frame.
|
||||
if !in_segment && !in_prev_segment {
|
||||
let mut segment = segment;
|
||||
while ptr::is_not_null((*segment).next) &&
|
||||
is_frame_in_segment(fp, (*segment).next) {
|
||||
segment = (*segment).next;
|
||||
}
|
||||
return Segment {segment: segment, boundary: false};
|
||||
}
|
||||
|
||||
// If frame is in previous frame, then we're at a boundary.
|
||||
if !in_segment && in_prev_segment {
|
||||
return Segment {segment: (*segment).prev, boundary: true};
|
||||
}
|
||||
|
||||
// Otherwise, we're somewhere on the inside of the frame.
|
||||
return Segment {segment: segment, boundary: false};
|
||||
}
|
||||
|
||||
type Memory = uint;
|
||||
|
||||
static task_local_heap: Memory = 1;
|
||||
static exchange_heap: Memory = 2;
|
||||
static stack: Memory = 4;
|
||||
|
||||
static need_cleanup: Memory = exchange_heap | stack;
|
||||
|
||||
// Walks stack, searching for roots of the requested type, and passes
|
||||
// each root to the visitor.
|
||||
unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
|
||||
let mut segment = rustrt::rust_get_stack_segment();
|
||||
let mut last_ret: *Word = ptr::null();
|
||||
// To avoid collecting memory used by the GC itself, skip stack
|
||||
// frames until past the root GC stack frame. The root GC stack
|
||||
// frame is marked by a sentinel, which is a box pointer stored on
|
||||
// the stack.
|
||||
let mut reached_sentinel = ptr::is_null(sentinel);
|
||||
for stackwalk::walk_stack |frame| {
|
||||
unsafe {
|
||||
let pc = last_ret;
|
||||
let Segment {segment: next_segment, boundary: boundary} =
|
||||
find_segment_for_frame(frame.fp, segment);
|
||||
segment = next_segment;
|
||||
// Each stack segment is bounded by a morestack frame. The
|
||||
// morestack frame includes two return addresses, one for
|
||||
// morestack itself, at the normal offset from the frame
|
||||
// pointer, and then a second return address for the
|
||||
// function prologue (which called morestack after
|
||||
// determining that it had hit the end of the stack).
|
||||
// Since morestack itself takes two parameters, the offset
|
||||
// for this second return address is 3 greater than the
|
||||
// return address for morestack.
|
||||
let ret_offset = if boundary { 4 } else { 1 };
|
||||
last_ret = *ptr::offset(frame.fp, ret_offset) as *Word;
|
||||
|
||||
if ptr::is_null(pc) {
|
||||
loop;
|
||||
}
|
||||
|
||||
let mut delay_reached_sentinel = reached_sentinel;
|
||||
let sp = is_safe_point(pc);
|
||||
match sp {
|
||||
Some(sp_info) => {
|
||||
for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
|
||||
// Skip roots until we see the sentinel.
|
||||
if !reached_sentinel {
|
||||
if root == sentinel {
|
||||
delay_reached_sentinel = true;
|
||||
}
|
||||
loop;
|
||||
}
|
||||
|
||||
// Skip null pointers, which can occur when a
|
||||
// unique pointer has already been freed.
|
||||
if ptr::is_null(*root) {
|
||||
loop;
|
||||
}
|
||||
|
||||
if ptr::is_null(tydesc) {
|
||||
// Root is a generic box.
|
||||
let refcount = **root;
|
||||
if mem | task_local_heap != 0 && refcount != -1 {
|
||||
if !visitor(root, tydesc) { return; }
|
||||
} else if mem | exchange_heap != 0 && refcount == -1 {
|
||||
if !visitor(root, tydesc) { return; }
|
||||
}
|
||||
} else {
|
||||
// Root is a non-immediate.
|
||||
if mem | stack != 0 {
|
||||
if !visitor(root, tydesc) { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
reached_sentinel = delay_reached_sentinel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gc() {
|
||||
unsafe {
|
||||
// Abort when GC is disabled.
|
||||
if get_safe_point_count() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
for walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| {
|
||||
// FIXME(#2997): Walk roots and mark them.
|
||||
io::stdout().write([46]); // .
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(gc)]
|
||||
fn expect_sentinel() -> bool { true }
|
||||
|
||||
#[cfg(nogc)]
|
||||
fn expect_sentinel() -> bool { false }
|
||||
|
||||
// Entry point for GC-based cleanup. Walks stack looking for exchange
|
||||
// heap and stack allocations requiring drop, and runs all
|
||||
// destructors.
|
||||
//
|
||||
// This should only be called from fail!, as it will drop the roots
|
||||
// which are *live* on the stack, rather than dropping those that are
|
||||
// dead.
|
||||
pub fn cleanup_stack_for_failure() {
|
||||
unsafe {
|
||||
// Abort when GC is disabled.
|
||||
if get_safe_point_count() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave a sentinel on the stack to mark the current frame. The
|
||||
// stack walker will ignore any frames above the sentinel, thus
|
||||
// avoiding collecting any memory being used by the stack walker
|
||||
// itself.
|
||||
//
|
||||
// However, when core itself is not compiled with GC, then none of
|
||||
// the functions in core will have GC metadata, which means we
|
||||
// won't be able to find the sentinel root on the stack. In this
|
||||
// case, we can safely skip the sentinel since we won't find our
|
||||
// own stack roots on the stack anyway.
|
||||
let sentinel_box = ~0;
|
||||
let sentinel: **Word = if expect_sentinel() {
|
||||
cast::reinterpret_cast(&ptr::addr_of(&sentinel_box))
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
let mut roots = LinearSet::new();
|
||||
for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| {
|
||||
// Track roots to avoid double frees.
|
||||
if roots.contains(&*root) {
|
||||
loop;
|
||||
}
|
||||
roots.insert(*root);
|
||||
|
||||
if ptr::is_null(tydesc) {
|
||||
// FIXME #4420: Destroy this box
|
||||
// FIXME #4330: Destroy this box
|
||||
} else {
|
||||
rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,536 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* Implementation of SipHash 2-4
|
||||
*
|
||||
* See: http://131002.net/siphash/
|
||||
*
|
||||
* Consider this as a main "general-purpose" hash for all hashtables: it
|
||||
* runs at good speed (competitive with spooky and city) and permits
|
||||
* cryptographically strong _keyed_ hashing. Key your hashtables from a
|
||||
* CPRNG like rand::rng.
|
||||
*/
|
||||
|
||||
use io;
|
||||
use io::Writer;
|
||||
use to_bytes::IterBytes;
|
||||
use uint;
|
||||
use vec;
|
||||
|
||||
/**
|
||||
* Types that can meaningfully be hashed should implement this.
|
||||
*
|
||||
* Note that this trait is likely to change somewhat as it is
|
||||
* closely related to `to_bytes::IterBytes` and in almost all
|
||||
* cases presently the two are (and must be) used together.
|
||||
*
|
||||
* In general, most types only need to implement `IterBytes`,
|
||||
* and the implementation of `Hash` below will take care of
|
||||
* the rest. This is the recommended approach, since constructing
|
||||
* good keyed hash functions is quite difficult.
|
||||
*/
|
||||
pub trait Hash {
|
||||
/**
|
||||
* Compute a "keyed" hash of the value implementing the trait,
|
||||
* taking `k0` and `k1` as "keying" parameters that randomize or
|
||||
* otherwise perturb the hash function in such a way that a
|
||||
* hash table built using such "keyed hash functions" cannot
|
||||
* be made to perform linearly by an attacker controlling the
|
||||
* hashtable's contents.
|
||||
*
|
||||
* In practical terms, we implement this using the SipHash 2-4
|
||||
* function and require most types to only implement the
|
||||
* IterBytes trait, that feeds SipHash.
|
||||
*/
|
||||
fn hash_keyed(&self, k0: u64, k1: u64) -> u64;
|
||||
}
|
||||
|
||||
// When we have default methods, won't need this.
|
||||
pub trait HashUtil {
|
||||
fn hash(&self) -> u64;
|
||||
}
|
||||
|
||||
impl<A:Hash> HashUtil for A {
|
||||
#[inline(always)]
|
||||
fn hash(&self) -> u64 { self.hash_keyed(0,0) }
|
||||
}
|
||||
|
||||
/// Streaming hash-functions should implement this.
|
||||
pub trait Streaming {
|
||||
fn input(&self, (&const [u8]));
|
||||
// These can be refactored some when we have default methods.
|
||||
fn result_bytes(&self) -> ~[u8];
|
||||
fn result_str(&self) -> ~str;
|
||||
fn result_u64(&self) -> u64;
|
||||
fn reset(&self);
|
||||
}
|
||||
|
||||
impl<A:IterBytes> Hash for A {
|
||||
#[inline(always)]
|
||||
fn hash_keyed(&self, k0: u64, k1: u64) -> u64 {
|
||||
unsafe {
|
||||
let s = &State(k0, k1);
|
||||
for self.iter_bytes(true) |bytes| {
|
||||
s.input(bytes);
|
||||
}
|
||||
s.result_u64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_keyed_2<A: IterBytes,
|
||||
B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 {
|
||||
unsafe {
|
||||
let s = &State(k0, k1);
|
||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
s.result_u64()
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_keyed_3<A: IterBytes,
|
||||
B: IterBytes,
|
||||
C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 {
|
||||
unsafe {
|
||||
let s = &State(k0, k1);
|
||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
s.result_u64()
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_keyed_4<A: IterBytes,
|
||||
B: IterBytes,
|
||||
C: IterBytes,
|
||||
D: IterBytes>(a: &A, b: &B, c: &C, d: &D, k0: u64, k1: u64)
|
||||
-> u64 {
|
||||
unsafe {
|
||||
let s = &State(k0, k1);
|
||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for d.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
s.result_u64()
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_keyed_5<A: IterBytes,
|
||||
B: IterBytes,
|
||||
C: IterBytes,
|
||||
D: IterBytes,
|
||||
E: IterBytes>(a: &A, b: &B, c: &C, d: &D, e: &E,
|
||||
k0: u64, k1: u64) -> u64 {
|
||||
unsafe {
|
||||
let s = &State(k0, k1);
|
||||
for a.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for b.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for c.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for d.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
for e.iter_bytes(true) |bytes| { s.input(bytes); }
|
||||
s.result_u64()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement State as SipState
|
||||
|
||||
pub type State = SipState;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn State(k0: u64, k1: u64) -> State {
|
||||
SipState(k0, k1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn default_state() -> State {
|
||||
State(0,0)
|
||||
}
|
||||
|
||||
struct SipState {
|
||||
k0: u64,
|
||||
k1: u64,
|
||||
mut length: uint, // how many bytes we've processed
|
||||
mut v0: u64, // hash state
|
||||
mut v1: u64,
|
||||
mut v2: u64,
|
||||
mut v3: u64,
|
||||
mut tail: [u8, ..8], // unprocessed bytes
|
||||
mut ntail: uint, // how many bytes in tail are valid
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn SipState(key0: u64, key1: u64) -> SipState {
|
||||
let state = SipState {
|
||||
k0 : key0,
|
||||
k1 : key1,
|
||||
mut length : 0u,
|
||||
mut v0 : 0u64,
|
||||
mut v1 : 0u64,
|
||||
mut v2 : 0u64,
|
||||
mut v3 : 0u64,
|
||||
mut tail : [0u8,0,0,0,0,0,0,0],
|
||||
mut ntail : 0u,
|
||||
};
|
||||
(&state).reset();
|
||||
state
|
||||
}
|
||||
|
||||
// sadly, these macro definitions can't appear later,
|
||||
// because they're needed in the following defs;
|
||||
// this design could be improved.
|
||||
|
||||
macro_rules! u8to64_le (
|
||||
($buf:expr, $i:expr) =>
|
||||
($buf[0+$i] as u64 |
|
||||
$buf[1+$i] as u64 << 8 |
|
||||
$buf[2+$i] as u64 << 16 |
|
||||
$buf[3+$i] as u64 << 24 |
|
||||
$buf[4+$i] as u64 << 32 |
|
||||
$buf[5+$i] as u64 << 40 |
|
||||
$buf[6+$i] as u64 << 48 |
|
||||
$buf[7+$i] as u64 << 56)
|
||||
)
|
||||
|
||||
macro_rules! rotl (
|
||||
($x:expr, $b:expr) =>
|
||||
(($x << $b) | ($x >> (64 - $b)))
|
||||
)
|
||||
|
||||
macro_rules! compress (
|
||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
||||
({
|
||||
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
||||
$v0 = rotl!($v0, 32);
|
||||
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
||||
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
||||
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
||||
$v2 = rotl!($v2, 32);
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
impl io::Writer for SipState {
|
||||
|
||||
// Methods for io::writer
|
||||
#[inline(always)]
|
||||
fn write(&self, msg: &const [u8]) {
|
||||
|
||||
let length = msg.len();
|
||||
self.length += length;
|
||||
|
||||
let mut needed = 0u;
|
||||
|
||||
if self.ntail != 0 {
|
||||
needed = 8 - self.ntail;
|
||||
|
||||
if length < needed {
|
||||
let mut t = 0;
|
||||
while t < length {
|
||||
self.tail[self.ntail+t] = msg[t];
|
||||
t += 1;
|
||||
}
|
||||
self.ntail += length;
|
||||
return;
|
||||
}
|
||||
|
||||
let mut t = 0;
|
||||
while t < needed {
|
||||
self.tail[self.ntail+t] = msg[t];
|
||||
t += 1;
|
||||
}
|
||||
|
||||
let m = u8to64_le!(self.tail, 0);
|
||||
|
||||
self.v3 ^= m;
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
self.v0 ^= m;
|
||||
|
||||
self.ntail = 0;
|
||||
}
|
||||
|
||||
// Buffered tail is now flushed, process new input.
|
||||
let len = length - needed;
|
||||
let end = len & (!0x7);
|
||||
let left = len & 0x7;
|
||||
|
||||
let mut i = needed;
|
||||
while i < end {
|
||||
let mi = u8to64_le!(msg, i);
|
||||
|
||||
self.v3 ^= mi;
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
self.v0 ^= mi;
|
||||
|
||||
i += 8;
|
||||
}
|
||||
|
||||
let mut t = 0u;
|
||||
while t < left {
|
||||
self.tail[t] = msg[i+t];
|
||||
t += 1
|
||||
}
|
||||
self.ntail = left;
|
||||
}
|
||||
|
||||
fn seek(&self, _x: int, _s: io::SeekStyle) {
|
||||
fail!();
|
||||
}
|
||||
fn tell(&self) -> uint {
|
||||
self.length
|
||||
}
|
||||
fn flush(&self) -> int {
|
||||
0
|
||||
}
|
||||
fn get_type(&self) -> io::WriterType {
|
||||
io::File
|
||||
}
|
||||
}
|
||||
|
||||
impl Streaming for SipState {
|
||||
|
||||
#[inline(always)]
|
||||
fn input(&self, buf: &const [u8]) {
|
||||
self.write(buf);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn result_u64(&self) -> u64 {
|
||||
let mut v0 = self.v0;
|
||||
let mut v1 = self.v1;
|
||||
let mut v2 = self.v2;
|
||||
let mut v3 = self.v3;
|
||||
|
||||
let mut b : u64 = (self.length as u64 & 0xff) << 56;
|
||||
|
||||
if self.ntail > 0 { b |= self.tail[0] as u64 << 0; }
|
||||
if self.ntail > 1 { b |= self.tail[1] as u64 << 8; }
|
||||
if self.ntail > 2 { b |= self.tail[2] as u64 << 16; }
|
||||
if self.ntail > 3 { b |= self.tail[3] as u64 << 24; }
|
||||
if self.ntail > 4 { b |= self.tail[4] as u64 << 32; }
|
||||
if self.ntail > 5 { b |= self.tail[5] as u64 << 40; }
|
||||
if self.ntail > 6 { b |= self.tail[6] as u64 << 48; }
|
||||
|
||||
v3 ^= b;
|
||||
compress!(v0, v1, v2, v3);
|
||||
compress!(v0, v1, v2, v3);
|
||||
v0 ^= b;
|
||||
|
||||
v2 ^= 0xff;
|
||||
compress!(v0, v1, v2, v3);
|
||||
compress!(v0, v1, v2, v3);
|
||||
compress!(v0, v1, v2, v3);
|
||||
compress!(v0, v1, v2, v3);
|
||||
|
||||
return (v0 ^ v1 ^ v2 ^ v3);
|
||||
}
|
||||
|
||||
fn result_bytes(&self) -> ~[u8] {
|
||||
let h = self.result_u64();
|
||||
~[(h >> 0) as u8,
|
||||
(h >> 8) as u8,
|
||||
(h >> 16) as u8,
|
||||
(h >> 24) as u8,
|
||||
(h >> 32) as u8,
|
||||
(h >> 40) as u8,
|
||||
(h >> 48) as u8,
|
||||
(h >> 56) as u8,
|
||||
]
|
||||
}
|
||||
|
||||
fn result_str(&self) -> ~str {
|
||||
let r = self.result_bytes();
|
||||
let mut s = ~"";
|
||||
for vec::each(r) |b| {
|
||||
s += uint::to_str_radix(*b as uint, 16u);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn reset(&self) {
|
||||
self.length = 0;
|
||||
self.v0 = self.k0 ^ 0x736f6d6570736575;
|
||||
self.v1 = self.k1 ^ 0x646f72616e646f6d;
|
||||
self.v2 = self.k0 ^ 0x6c7967656e657261;
|
||||
self.v3 = self.k1 ^ 0x7465646279746573;
|
||||
self.ntail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_siphash() {
|
||||
let vecs : [[u8, ..8], ..64] = [
|
||||
[ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ],
|
||||
[ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ],
|
||||
[ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ],
|
||||
[ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ],
|
||||
[ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ],
|
||||
[ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ],
|
||||
[ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ],
|
||||
[ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ],
|
||||
[ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ],
|
||||
[ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ],
|
||||
[ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ],
|
||||
[ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ],
|
||||
[ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ],
|
||||
[ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ],
|
||||
[ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ],
|
||||
[ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ],
|
||||
[ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ],
|
||||
[ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ],
|
||||
[ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ],
|
||||
[ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ],
|
||||
[ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ],
|
||||
[ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ],
|
||||
[ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ],
|
||||
[ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ],
|
||||
[ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ],
|
||||
[ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ],
|
||||
[ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ],
|
||||
[ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ],
|
||||
[ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ],
|
||||
[ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ],
|
||||
[ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ],
|
||||
[ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ],
|
||||
[ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ],
|
||||
[ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ],
|
||||
[ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ],
|
||||
[ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ],
|
||||
[ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ],
|
||||
[ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ],
|
||||
[ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ],
|
||||
[ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ],
|
||||
[ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ],
|
||||
[ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ],
|
||||
[ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ],
|
||||
[ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ],
|
||||
[ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ],
|
||||
[ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ],
|
||||
[ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ],
|
||||
[ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ],
|
||||
[ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ],
|
||||
[ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ],
|
||||
[ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ],
|
||||
[ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ],
|
||||
[ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ],
|
||||
[ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ],
|
||||
[ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ],
|
||||
[ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ],
|
||||
[ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ],
|
||||
[ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ],
|
||||
[ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ],
|
||||
[ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ],
|
||||
[ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ],
|
||||
[ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ],
|
||||
[ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ],
|
||||
[ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]
|
||||
];
|
||||
|
||||
let k0 = 0x_07_06_05_04_03_02_01_00_u64;
|
||||
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64;
|
||||
let mut buf : ~[u8] = ~[];
|
||||
let mut t = 0;
|
||||
let stream_inc = &State(k0,k1);
|
||||
let stream_full = &State(k0,k1);
|
||||
|
||||
fn to_hex_str(r: &[u8, ..8]) -> ~str {
|
||||
let mut s = ~"";
|
||||
for vec::each(*r) |b| {
|
||||
s += uint::to_str_radix(*b as uint, 16u);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
while t < 64 {
|
||||
debug!("siphash test %?", t);
|
||||
let vec = u8to64_le!(vecs[t], 0);
|
||||
let out = buf.hash_keyed(k0, k1);
|
||||
debug!("got %?, expected %?", out, vec);
|
||||
assert!(vec == out);
|
||||
|
||||
stream_full.reset();
|
||||
stream_full.input(buf);
|
||||
let f = stream_full.result_str();
|
||||
let i = stream_inc.result_str();
|
||||
let v = to_hex_str(&vecs[t]);
|
||||
debug!("%d: (%s) => inc=%s full=%s", t, v, i, f);
|
||||
|
||||
assert!(f == i && f == v);
|
||||
|
||||
buf += ~[t as u8];
|
||||
stream_inc.input(~[t as u8]);
|
||||
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test] #[cfg(target_arch = "arm")]
|
||||
pub fn test_hash_uint() {
|
||||
let val = 0xdeadbeef_deadbeef_u64;
|
||||
assert!((val as u64).hash() != (val as uint).hash());
|
||||
assert!((val as u32).hash() == (val as uint).hash());
|
||||
}
|
||||
#[test] #[cfg(target_arch = "x86_64")]
|
||||
pub fn test_hash_uint() {
|
||||
let val = 0xdeadbeef_deadbeef_u64;
|
||||
assert!((val as u64).hash() == (val as uint).hash());
|
||||
assert!((val as u32).hash() != (val as uint).hash());
|
||||
}
|
||||
#[test] #[cfg(target_arch = "x86")]
|
||||
pub fn test_hash_uint() {
|
||||
let val = 0xdeadbeef_deadbeef_u64;
|
||||
assert!((val as u64).hash() != (val as uint).hash());
|
||||
assert!((val as u32).hash() == (val as uint).hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_idempotent() {
|
||||
let val64 = 0xdeadbeef_deadbeef_u64;
|
||||
val64.hash() == val64.hash();
|
||||
let val32 = 0xdeadbeef_u32;
|
||||
val32.hash() == val32.hash();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_no_bytes_dropped_64() {
|
||||
let val = 0xdeadbeef_deadbeef_u64;
|
||||
|
||||
assert!(val.hash() != zero_byte(val, 0).hash());
|
||||
assert!(val.hash() != zero_byte(val, 1).hash());
|
||||
assert!(val.hash() != zero_byte(val, 2).hash());
|
||||
assert!(val.hash() != zero_byte(val, 3).hash());
|
||||
assert!(val.hash() != zero_byte(val, 4).hash());
|
||||
assert!(val.hash() != zero_byte(val, 5).hash());
|
||||
assert!(val.hash() != zero_byte(val, 6).hash());
|
||||
assert!(val.hash() != zero_byte(val, 7).hash());
|
||||
|
||||
fn zero_byte(val: u64, byte: uint) -> u64 {
|
||||
assert!(byte < 8);
|
||||
val & !(0xff << (byte * 8))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_no_bytes_dropped_32() {
|
||||
let val = 0xdeadbeef_u32;
|
||||
|
||||
assert!(val.hash() != zero_byte(val, 0).hash());
|
||||
assert!(val.hash() != zero_byte(val, 1).hash());
|
||||
assert!(val.hash() != zero_byte(val, 2).hash());
|
||||
assert!(val.hash() != zero_byte(val, 3).hash());
|
||||
|
||||
fn zero_byte(val: u32, byte: uint) -> u32 {
|
||||
assert!(byte < 4);
|
||||
val & !(0xff << (byte * 8))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
1616
src/libcore/io.rs
1616
src/libcore/io.rs
File diff suppressed because it is too large
Load Diff
@ -1,346 +0,0 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
|
||||
The iteration traits and common implementation
|
||||
|
||||
*/
|
||||
|
||||
use cmp::{Eq, Ord};
|
||||
use kinds::Copy;
|
||||
use option::{None, Option, Some};
|
||||
use vec;
|
||||
|
||||
/// A function used to initialize the elements of a sequence
|
||||
pub type InitOp<'self,T> = &'self fn(uint) -> T;
|
||||
|
||||
pub trait BaseIter<A> {
|
||||
fn each(&self, blk: &fn(v: &A) -> bool);
|
||||
fn size_hint(&self) -> Option<uint>;
|
||||
}
|
||||
|
||||
pub trait ReverseIter<A>: BaseIter<A> {
|
||||
fn each_reverse(&self, blk: &fn(&A) -> bool);
|
||||
}
|
||||
|
||||
pub trait MutableIter<A>: BaseIter<A> {
|
||||
fn each_mut(&mut self, blk: &fn(&mut A) -> bool);
|
||||
}
|
||||
|
||||
pub trait ExtendedIter<A> {
|
||||
fn eachi(&self, blk: &fn(uint, v: &A) -> bool);
|
||||
fn all(&self, blk: &fn(&A) -> bool) -> bool;
|
||||
fn any(&self, blk: &fn(&A) -> bool) -> bool;
|
||||
fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B;
|
||||
fn position(&self, f: &fn(&A) -> bool) -> Option<uint>;
|
||||
fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B];
|
||||
fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B];
|
||||
}
|
||||
|
||||
pub trait EqIter<A:Eq> {
|
||||
fn contains(&self, x: &A) -> bool;
|
||||
fn count(&self, x: &A) -> uint;
|
||||
}
|
||||
|
||||
pub trait Times {
|
||||
fn times(&self, it: &fn() -> bool);
|
||||
}
|
||||
|
||||
pub trait CopyableIter<A:Copy> {
|
||||
fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A];
|
||||
fn to_vec(&self) -> ~[A];
|
||||
fn find(&self, p: &fn(&A) -> bool) -> Option<A>;
|
||||
}
|
||||
|
||||
pub trait CopyableOrderedIter<A:Copy + Ord> {
|
||||
fn min(&self) -> A;
|
||||
fn max(&self) -> A;
|
||||
}
|
||||
|
||||
pub trait CopyableNonstrictIter<A:Copy> {
|
||||
// Like "each", but copies out the value. If the receiver is mutated while
|
||||
// iterating over it, the semantics must not be memory-unsafe but are
|
||||
// otherwise undefined.
|
||||
fn each_val(&const self, f: &fn(A) -> bool);
|
||||
}
|
||||
|
||||
// A trait for sequences that can be built by imperatively pushing elements
|
||||
// onto them.
|
||||
pub trait Buildable<A> {
|
||||
/**
|
||||
* Builds a buildable sequence by calling a provided function with
|
||||
* an argument function that pushes an element onto the back of
|
||||
* the sequence.
|
||||
* This version takes an initial size for the sequence.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * size - A hint for an initial size of the sequence
|
||||
* * builder - A function that will construct the sequence. It receives
|
||||
* as an argument a function that will push an element
|
||||
* onto the sequence being constructed.
|
||||
*/
|
||||
fn build_sized(size: uint, builder: &fn(push: &fn(A))) -> Self;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn eachi<A,IA:BaseIter<A>>(self: &IA, blk: &fn(uint, &A) -> bool) {
|
||||
let mut i = 0;
|
||||
for self.each |a| {
|
||||
if !blk(i, a) { break; }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn all<A,IA:BaseIter<A>>(self: &IA, blk: &fn(&A) -> bool) -> bool {
|
||||
for self.each |a| {
|
||||
if !blk(a) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn any<A,IA:BaseIter<A>>(self: &IA, blk: &fn(&A) -> bool) -> bool {
|
||||
for self.each |a| {
|
||||
if blk(a) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn filter_to_vec<A:Copy,IA:BaseIter<A>>(self: &IA,
|
||||
prd: &fn(&A) -> bool)
|
||||
-> ~[A] {
|
||||
do vec::build_sized_opt(self.size_hint()) |push| {
|
||||
for self.each |a| {
|
||||
if prd(a) { push(*a); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn map_to_vec<A,B,IA:BaseIter<A>>(self: &IA, op: &fn(&A) -> B) -> ~[B] {
|
||||
do vec::build_sized_opt(self.size_hint()) |push| {
|
||||
for self.each |a| {
|
||||
push(op(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(self: &IA,
|
||||
op: &fn(&A) -> IB)
|
||||
-> ~[B] {
|
||||
do vec::build |push| {
|
||||
for self.each |a| {
|
||||
for op(a).each |&b| {
|
||||
push(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn foldl<A,B,IA:BaseIter<A>>(self: &IA, b0: B, blk: &fn(&B, &A) -> B)
|
||||
-> B {
|
||||
let mut b = b0;
|
||||
for self.each |a| {
|
||||
b = blk(&b, a);
|
||||
}
|
||||
b
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_vec<A:Copy,IA:BaseIter<A>>(self: &IA) -> ~[A] {
|
||||
foldl::<A,~[A],IA>(self, ~[], |r, a| vec::append(copy (*r), ~[*a]))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn contains<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> bool {
|
||||
for self.each |a| {
|
||||
if *a == *x { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn count<A:Eq,IA:BaseIter<A>>(self: &IA, x: &A) -> uint {
|
||||
do foldl(self, 0) |count, value| {
|
||||
if *value == *x {
|
||||
*count + 1
|
||||
} else {
|
||||
*count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn position<A,IA:BaseIter<A>>(self: &IA, f: &fn(&A) -> bool)
|
||||
-> Option<uint> {
|
||||
let mut i = 0;
|
||||
for self.each |a| {
|
||||
if f(a) { return Some(i); }
|
||||
i += 1;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// note: 'rposition' would only make sense to provide with a bidirectional
|
||||
// iter interface, such as would provide "reach" in addition to "each". As is,
|
||||
// it would have to be implemented with foldr, which is too inefficient.
|
||||
|
||||
#[inline(always)]
|
||||
pub fn repeat(times: uint, blk: &fn() -> bool) {
|
||||
let mut i = 0;
|
||||
while i < times {
|
||||
if !blk() { break }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn min<A:Copy + Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
||||
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
||||
match a {
|
||||
&Some(ref a_) if *a_ < *b => {
|
||||
*(a)
|
||||
}
|
||||
_ => Some(*b)
|
||||
}
|
||||
} {
|
||||
Some(val) => val,
|
||||
None => fail!(~"min called on empty iterator")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn max<A:Copy + Ord,IA:BaseIter<A>>(self: &IA) -> A {
|
||||
match do foldl::<A,Option<A>,IA>(self, None) |a, b| {
|
||||
match a {
|
||||
&Some(ref a_) if *a_ > *b => {
|
||||
*(a)
|
||||
}
|
||||
_ => Some(*b)
|
||||
}
|
||||
} {
|
||||
Some(val) => val,
|
||||
None => fail!(~"max called on empty iterator")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn find<A:Copy,IA:BaseIter<A>>(self: &IA, f: &fn(&A) -> bool)
|
||||
-> Option<A> {
|
||||
for self.each |i| {
|
||||
if f(i) { return Some(*i) }
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Some functions for just building
|
||||
|
||||
/**
|
||||
* Builds a sequence by calling a provided function with an argument
|
||||
* function that pushes an element to the back of a sequence.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * builder - A function that will construct the sequence. It receives
|
||||
* as an argument a function that will push an element
|
||||
* onto the sequence being constructed.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn build<A,B: Buildable<A>>(builder: &fn(push: &fn(A))) -> B {
|
||||
Buildable::build_sized(4, builder)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a sequence by calling a provided function with an argument
|
||||
* function that pushes an element to the back of the sequence.
|
||||
* This version takes an initial size for the sequence.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * size - An option, maybe containing initial size of the sequence
|
||||
* to reserve.
|
||||
* * builder - A function that will construct the sequence. It receives
|
||||
* as an argument a function that will push an element
|
||||
* onto the sequence being constructed.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn build_sized_opt<A,B: Buildable<A>>(size: Option<uint>,
|
||||
builder: &fn(push: &fn(A))) -> B {
|
||||
Buildable::build_sized(size.get_or_default(4), builder)
|
||||
}
|
||||
|
||||
// Functions that combine iteration and building
|
||||
|
||||
/// Applies a function to each element of an iterable and returns the results
|
||||
/// in a sequence built via `BU`. See also `map_to_vec`.
|
||||
#[inline(always)]
|
||||
pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: &fn(&T) -> U)
|
||||
-> BU {
|
||||
do build_sized_opt(v.size_hint()) |push| {
|
||||
for v.each() |elem| {
|
||||
push(f(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a generic sequence from a function.
|
||||
*
|
||||
* Creates a generic sequence of size `n_elts` and initializes the elements
|
||||
* to the value returned by the function `op`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT {
|
||||
do Buildable::build_sized(n_elts) |push| {
|
||||
let mut i: uint = 0u;
|
||||
while i < n_elts { push(op(i)); i += 1u; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes a generic sequence with some elements.
|
||||
*
|
||||
* Creates an immutable vector of size `n_elts` and initializes the elements
|
||||
* to the value `t`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_elem<T:Copy,BT:Buildable<T>>(n_elts: uint, t: T) -> BT {
|
||||
do Buildable::build_sized(n_elts) |push| {
|
||||
let mut i: uint = 0;
|
||||
while i < n_elts { push(t); i += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends two generic sequences.
|
||||
#[inline(always)]
|
||||
pub fn append<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(lhs: &IT, rhs: &IT)
|
||||
-> BT {
|
||||
let size_opt = lhs.size_hint().chain_ref(
|
||||
|sz1| rhs.size_hint().map(|sz2| *sz1+*sz2));
|
||||
do build_sized_opt(size_opt) |push| {
|
||||
for lhs.each |x| { push(*x); }
|
||||
for rhs.each |x| { push(*x); }
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies a generic sequence, possibly converting it to a different
|
||||
/// type of sequence.
|
||||
#[inline(always)]
|
||||
pub fn copy_seq<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(v: &IT) -> BT {
|
||||
do build_sized_opt(v.size_hint()) |push| {
|
||||
for v.each |x| { push(*x); }
|
||||
}
|
||||
}
|
1689
src/libcore/libc.rs
1689
src/libcore/libc.rs
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Logging
|
||||
|
||||
pub mod rustrt {
|
||||
use libc;
|
||||
|
||||
pub extern {
|
||||
unsafe fn rust_log_console_on();
|
||||
unsafe fn rust_log_console_off();
|
||||
unsafe fn rust_log_str(level: u32,
|
||||
string: *libc::c_char,
|
||||
size: libc::size_t);
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns on logging to stdout globally
|
||||
pub fn console_on() {
|
||||
unsafe {
|
||||
rustrt::rust_log_console_on();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off logging to stdout globally
|
||||
*
|
||||
* Turns off the console unless the user has overridden the
|
||||
* runtime environment's logging spec, e.g. by setting
|
||||
* the RUST_LOG environment variable
|
||||
*/
|
||||
pub fn console_off() {
|
||||
unsafe {
|
||||
rustrt::rust_log_console_off();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
#[lang="log_type"]
|
||||
pub fn log_type<T>(level: u32, object: &T) {
|
||||
use cast::transmute;
|
||||
use io;
|
||||
use libc;
|
||||
use repr;
|
||||
use vec;
|
||||
|
||||
let bytes = do io::with_bytes_writer |writer| {
|
||||
repr::write_repr(writer, object);
|
||||
};
|
||||
unsafe {
|
||||
let len = bytes.len() as libc::size_t;
|
||||
rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len);
|
||||
}
|
||||
}
|
||||
|
@ -1,98 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations on managed box types
|
||||
|
||||
use ptr;
|
||||
|
||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
||||
|
||||
pub mod raw {
|
||||
use intrinsic::TyDesc;
|
||||
|
||||
pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint;
|
||||
pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
|
||||
pub static RC_IMMORTAL : uint = 0x77777777;
|
||||
|
||||
pub struct BoxHeaderRepr {
|
||||
ref_count: uint,
|
||||
type_desc: *TyDesc,
|
||||
prev: *BoxRepr,
|
||||
next: *BoxRepr,
|
||||
}
|
||||
|
||||
pub struct BoxRepr {
|
||||
header: BoxHeaderRepr,
|
||||
data: u8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ptr_eq<T>(a: @T, b: @T) -> bool {
|
||||
//! Determine if two shared boxes point to the same object
|
||||
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mut_ptr_eq<T>(a: @mut T, b: @mut T) -> bool {
|
||||
//! Determine if two mutable shared boxes point to the same object
|
||||
unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl<T:Eq> Eq for @T {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &@T) -> bool { *(*self) == *(*other) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &@T) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl<T:Eq> Eq for @mut T {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &@mut T) -> bool { *(*self) == *(*other) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &@mut T) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl<T:Ord> Ord for @T {
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &@T) -> bool { *(*self) < *(*other) }
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &@T) -> bool { *(*self) <= *(*other) }
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &@T) -> bool { *(*self) >= *(*other) }
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &@T) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl<T:Ord> Ord for @mut T {
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &@mut T) -> bool { *(*self) < *(*other) }
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &@mut T) -> bool { *(*self) <= *(*other) }
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &@mut T) -> bool { *(*self) >= *(*other) }
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let x = @3;
|
||||
let y = @3;
|
||||
assert!((ptr_eq::<int>(x, x)));
|
||||
assert!((ptr_eq::<int>(y, y)));
|
||||
assert!((!ptr_eq::<int>(x, y)));
|
||||
assert!((!ptr_eq::<int>(y, x)));
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
|
||||
Module for wrapping freezable data structures in managed boxes.
|
||||
Normally freezable data structures require an unaliased reference,
|
||||
such as `T` or `~T`, so that the compiler can track when they are
|
||||
being mutated. The `managed<T>` type converts these static checks into
|
||||
dynamic checks: your program will fail if you attempt to perform
|
||||
mutation when the data structure should be immutable.
|
||||
|
||||
*/
|
||||
|
||||
use util::with;
|
||||
use cast::transmute_immut;
|
||||
|
||||
enum Mode { ReadOnly, Mutable, Immutable }
|
||||
|
||||
struct Data<T> {
|
||||
priv mut value: T,
|
||||
priv mut mode: Mode
|
||||
}
|
||||
|
||||
pub type Mut<T> = Data<T>;
|
||||
|
||||
pub fn Mut<T>(t: T) -> Mut<T> {
|
||||
Data {value: t, mode: ReadOnly}
|
||||
}
|
||||
|
||||
pub fn unwrap<T>(m: Mut<T>) -> T {
|
||||
// Borrowck should prevent us from calling unwrap while the value
|
||||
// is in use, as that would be a move from a borrowed value.
|
||||
assert!((m.mode as uint) == (ReadOnly as uint));
|
||||
let Data {value: value, mode: _} = m;
|
||||
value
|
||||
}
|
||||
|
||||
pub impl<T> Data<T> {
|
||||
fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R {
|
||||
match self.mode {
|
||||
Immutable => fail!(~"currently immutable"),
|
||||
ReadOnly | Mutable => {}
|
||||
}
|
||||
|
||||
do with(&mut self.mode, Mutable) {
|
||||
op(&mut self.value)
|
||||
}
|
||||
}
|
||||
|
||||
fn borrow_const<R>(&self, op: &fn(t: &const T) -> R) -> R {
|
||||
op(&const self.value)
|
||||
}
|
||||
|
||||
fn borrow_imm<R>(&self, op: &fn(t: &T) -> R) -> R {
|
||||
match self.mode {
|
||||
Mutable => fail!(~"currently mutable"),
|
||||
ReadOnly | Immutable => {}
|
||||
}
|
||||
|
||||
do with(&mut self.mode, Immutable) {
|
||||
op(unsafe{transmute_immut(&mut self.value)})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unwrap(self) -> T { unwrap(self) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore(cfg(windows))]
|
||||
#[should_fail]
|
||||
pub fn test_mut_in_imm() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_imm |_p| {
|
||||
do m.borrow_mut |_q| {
|
||||
// should not be permitted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore(cfg(windows))]
|
||||
#[should_fail]
|
||||
pub fn test_imm_in_mut() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_mut |_p| {
|
||||
do m.borrow_imm |_q| {
|
||||
// should not be permitted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_const_in_mut() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_mut |p| {
|
||||
do m.borrow_const |q| {
|
||||
assert!(*p == *q);
|
||||
*p += 1;
|
||||
assert!(*p == *q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_mut_in_const() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_const |p| {
|
||||
do m.borrow_mut |q| {
|
||||
assert!(*p == *q);
|
||||
*q += 1;
|
||||
assert!(*p == *q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_imm_in_const() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_const |p| {
|
||||
do m.borrow_imm |q| {
|
||||
assert!(*p == *q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_const_in_imm() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_imm |p| {
|
||||
do m.borrow_const |q| {
|
||||
assert!(*p == *q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[ignore(cfg(windows))]
|
||||
#[should_fail]
|
||||
pub fn test_mut_in_imm_in_const() {
|
||||
let m = @Mut(1);
|
||||
do m.borrow_const |_p| {
|
||||
do m.borrow_imm |_q| {
|
||||
do m.borrow_mut |_r| {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,648 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations and constants for `f32`
|
||||
|
||||
use cmath;
|
||||
use libc::{c_float, c_int};
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use option::Option;
|
||||
use unstable::intrinsics::floorf32;
|
||||
use from_str;
|
||||
use to_str;
|
||||
|
||||
#[cfg(notest)] use cmp;
|
||||
#[cfg(notest)] use ops;
|
||||
|
||||
pub use cmath::c_float_targ_consts::*;
|
||||
|
||||
macro_rules! delegate(
|
||||
(
|
||||
fn $name:ident(
|
||||
$(
|
||||
$arg:ident : $arg_ty:ty
|
||||
),*
|
||||
) -> $rv:ty = $bound_name:path
|
||||
) => (
|
||||
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
|
||||
unsafe {
|
||||
$bound_name($( $arg ),*)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
delegate!(fn acos(n: c_float) -> c_float = cmath::c_float_utils::acos)
|
||||
delegate!(fn asin(n: c_float) -> c_float = cmath::c_float_utils::asin)
|
||||
delegate!(fn atan(n: c_float) -> c_float = cmath::c_float_utils::atan)
|
||||
delegate!(fn atan2(a: c_float, b: c_float) -> c_float =
|
||||
cmath::c_float_utils::atan2)
|
||||
delegate!(fn cbrt(n: c_float) -> c_float = cmath::c_float_utils::cbrt)
|
||||
delegate!(fn ceil(n: c_float) -> c_float = cmath::c_float_utils::ceil)
|
||||
delegate!(fn copysign(x: c_float, y: c_float) -> c_float =
|
||||
cmath::c_float_utils::copysign)
|
||||
delegate!(fn cos(n: c_float) -> c_float = cmath::c_float_utils::cos)
|
||||
delegate!(fn cosh(n: c_float) -> c_float = cmath::c_float_utils::cosh)
|
||||
delegate!(fn erf(n: c_float) -> c_float = cmath::c_float_utils::erf)
|
||||
delegate!(fn erfc(n: c_float) -> c_float = cmath::c_float_utils::erfc)
|
||||
delegate!(fn exp(n: c_float) -> c_float = cmath::c_float_utils::exp)
|
||||
delegate!(fn expm1(n: c_float) -> c_float = cmath::c_float_utils::expm1)
|
||||
delegate!(fn exp2(n: c_float) -> c_float = cmath::c_float_utils::exp2)
|
||||
delegate!(fn abs(n: c_float) -> c_float = cmath::c_float_utils::abs)
|
||||
delegate!(fn abs_sub(a: c_float, b: c_float) -> c_float =
|
||||
cmath::c_float_utils::abs_sub)
|
||||
delegate!(fn mul_add(a: c_float, b: c_float, c: c_float) -> c_float =
|
||||
cmath::c_float_utils::mul_add)
|
||||
delegate!(fn fmax(a: c_float, b: c_float) -> c_float =
|
||||
cmath::c_float_utils::fmax)
|
||||
delegate!(fn fmin(a: c_float, b: c_float) -> c_float =
|
||||
cmath::c_float_utils::fmin)
|
||||
delegate!(fn nextafter(x: c_float, y: c_float) -> c_float =
|
||||
cmath::c_float_utils::nextafter)
|
||||
delegate!(fn frexp(n: c_float, value: &mut c_int) -> c_float =
|
||||
cmath::c_float_utils::frexp)
|
||||
delegate!(fn hypot(x: c_float, y: c_float) -> c_float =
|
||||
cmath::c_float_utils::hypot)
|
||||
delegate!(fn ldexp(x: c_float, n: c_int) -> c_float =
|
||||
cmath::c_float_utils::ldexp)
|
||||
delegate!(fn lgamma(n: c_float, sign: &mut c_int) -> c_float =
|
||||
cmath::c_float_utils::lgamma)
|
||||
delegate!(fn ln(n: c_float) -> c_float = cmath::c_float_utils::ln)
|
||||
delegate!(fn log_radix(n: c_float) -> c_float =
|
||||
cmath::c_float_utils::log_radix)
|
||||
delegate!(fn ln1p(n: c_float) -> c_float = cmath::c_float_utils::ln1p)
|
||||
delegate!(fn log10(n: c_float) -> c_float = cmath::c_float_utils::log10)
|
||||
delegate!(fn log2(n: c_float) -> c_float = cmath::c_float_utils::log2)
|
||||
delegate!(fn ilog_radix(n: c_float) -> c_int =
|
||||
cmath::c_float_utils::ilog_radix)
|
||||
delegate!(fn modf(n: c_float, iptr: &mut c_float) -> c_float =
|
||||
cmath::c_float_utils::modf)
|
||||
delegate!(fn pow(n: c_float, e: c_float) -> c_float =
|
||||
cmath::c_float_utils::pow)
|
||||
delegate!(fn round(n: c_float) -> c_float = cmath::c_float_utils::round)
|
||||
delegate!(fn ldexp_radix(n: c_float, i: c_int) -> c_float =
|
||||
cmath::c_float_utils::ldexp_radix)
|
||||
delegate!(fn sin(n: c_float) -> c_float = cmath::c_float_utils::sin)
|
||||
delegate!(fn sinh(n: c_float) -> c_float = cmath::c_float_utils::sinh)
|
||||
delegate!(fn sqrt(n: c_float) -> c_float = cmath::c_float_utils::sqrt)
|
||||
delegate!(fn tan(n: c_float) -> c_float = cmath::c_float_utils::tan)
|
||||
delegate!(fn tanh(n: c_float) -> c_float = cmath::c_float_utils::tanh)
|
||||
delegate!(fn tgamma(n: c_float) -> c_float = cmath::c_float_utils::tgamma)
|
||||
delegate!(fn trunc(n: c_float) -> c_float = cmath::c_float_utils::trunc)
|
||||
|
||||
// These are not defined inside consts:: for consistency with
|
||||
// the integer types
|
||||
|
||||
pub static NaN: f32 = 0.0_f32/0.0_f32;
|
||||
|
||||
pub static infinity: f32 = 1.0_f32/0.0_f32;
|
||||
|
||||
pub static neg_infinity: f32 = -1.0_f32/0.0_f32;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_NaN(f: f32) -> bool { f != f }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add(x: f32, y: f32) -> f32 { return x + y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub(x: f32, y: f32) -> f32 { return x - y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul(x: f32, y: f32) -> f32 { return x * y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn div(x: f32, y: f32) -> f32 { return x / y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn rem(x: f32, y: f32) -> f32 { return x % y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lt(x: f32, y: f32) -> bool { return x < y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn le(x: f32, y: f32) -> bool { return x <= y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn eq(x: f32, y: f32) -> bool { return x == y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ne(x: f32, y: f32) -> bool { return x != y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ge(x: f32, y: f32) -> bool { return x >= y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn gt(x: f32, y: f32) -> bool { return x > y; }
|
||||
|
||||
/// Returns `x` rounded down
|
||||
#[inline(always)]
|
||||
pub fn floor(x: f32) -> f32 { unsafe { floorf32(x) } }
|
||||
|
||||
// FIXME (#1999): replace the predicates below with llvm intrinsics or
|
||||
// calls to the libmath macros in the rust runtime for performance.
|
||||
|
||||
/// Returns true if `x` is a positive number, including +0.0f320 and +Infinity
|
||||
#[inline(always)]
|
||||
pub fn is_positive(x: f32) -> bool {
|
||||
x > 0.0f32 || (1.0f32/x) == infinity
|
||||
}
|
||||
|
||||
/// Returns true if `x` is a negative number, including -0.0f320 and -Infinity
|
||||
#[inline(always)]
|
||||
pub fn is_negative(x: f32) -> bool {
|
||||
x < 0.0f32 || (1.0f32/x) == neg_infinity
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `x` is a negative number, including -0.0f320 and -Infinity
|
||||
*
|
||||
* This is the same as `f32::is_negative`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_nonpositive(x: f32) -> bool {
|
||||
return x < 0.0f32 || (1.0f32/x) == neg_infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `x` is a positive number, including +0.0f320 and +Infinity
|
||||
*
|
||||
* This is the same as `f32::is_positive`.)
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_nonnegative(x: f32) -> bool {
|
||||
return x > 0.0f32 || (1.0f32/x) == infinity;
|
||||
}
|
||||
|
||||
/// Returns true if `x` is a zero number (positive or negative zero)
|
||||
#[inline(always)]
|
||||
pub fn is_zero(x: f32) -> bool {
|
||||
return x == 0.0f32 || x == -0.0f32;
|
||||
}
|
||||
|
||||
/// Returns true if `x`is an infinite number
|
||||
#[inline(always)]
|
||||
pub fn is_infinite(x: f32) -> bool {
|
||||
return x == infinity || x == neg_infinity;
|
||||
}
|
||||
|
||||
/// Returns true if `x`is a finite number
|
||||
#[inline(always)]
|
||||
pub fn is_finite(x: f32) -> bool {
|
||||
return !(is_NaN(x) || is_infinite(x));
|
||||
}
|
||||
|
||||
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify.
|
||||
|
||||
/* Module: consts */
|
||||
pub mod consts {
|
||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
||||
// staticants from cmath.
|
||||
/// Archimedes' staticant
|
||||
pub static pi: f32 = 3.14159265358979323846264338327950288_f32;
|
||||
|
||||
/// pi/2.0
|
||||
pub static frac_pi_2: f32 = 1.57079632679489661923132169163975144_f32;
|
||||
|
||||
/// pi/4.0
|
||||
pub static frac_pi_4: f32 = 0.785398163397448309615660845819875721_f32;
|
||||
|
||||
/// 1.0/pi
|
||||
pub static frac_1_pi: f32 = 0.318309886183790671537767526745028724_f32;
|
||||
|
||||
/// 2.0/pi
|
||||
pub static frac_2_pi: f32 = 0.636619772367581343075535053490057448_f32;
|
||||
|
||||
/// 2.0/sqrt(pi)
|
||||
pub static frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517_f32;
|
||||
|
||||
/// sqrt(2.0)
|
||||
pub static sqrt2: f32 = 1.41421356237309504880168872420969808_f32;
|
||||
|
||||
/// 1.0/sqrt(2.0)
|
||||
pub static frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039_f32;
|
||||
|
||||
/// Euler's number
|
||||
pub static e: f32 = 2.71828182845904523536028747135266250_f32;
|
||||
|
||||
/// log2(e)
|
||||
pub static log2_e: f32 = 1.44269504088896340735992468100189214_f32;
|
||||
|
||||
/// log10(e)
|
||||
pub static log10_e: f32 = 0.434294481903251827651128918916605082_f32;
|
||||
|
||||
/// ln(2.0)
|
||||
pub static ln_2: f32 = 0.693147180559945309417232121458176568_f32;
|
||||
|
||||
/// ln(10.0)
|
||||
pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn signbit(x: f32) -> int {
|
||||
if is_negative(x) { return 1; } else { return 0; }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn logarithm(n: f32, b: f32) -> f32 {
|
||||
return log2(n) / log2(b);
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl cmp::Eq for f32 {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &f32) -> bool { (*self) == (*other) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &f32) -> bool { (*self) != (*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl cmp::Ord for f32 {
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &f32) -> bool { (*self) < (*other) }
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &f32) -> bool { (*self) <= (*other) }
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &f32) -> bool { (*self) >= (*other) }
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &f32) -> bool { (*self) > (*other) }
|
||||
}
|
||||
|
||||
impl num::Zero for f32 {
|
||||
#[inline(always)]
|
||||
fn zero() -> f32 { 0.0 }
|
||||
}
|
||||
|
||||
impl num::One for f32 {
|
||||
#[inline(always)]
|
||||
fn one() -> f32 { 1.0 }
|
||||
}
|
||||
|
||||
impl NumCast for f32 {
|
||||
/**
|
||||
* Cast `n` to an `f32`
|
||||
*/
|
||||
#[inline(always)]
|
||||
fn from<N:NumCast>(n: N) -> f32 { n.to_f32() }
|
||||
|
||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
||||
|
||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
||||
|
||||
#[inline(always)] fn to_f32(&self) -> f32 { *self }
|
||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<f32,f32> for f32 {
|
||||
fn add(&self, other: &f32) -> f32 { *self + *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Sub<f32,f32> for f32 {
|
||||
fn sub(&self, other: &f32) -> f32 { *self - *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Mul<f32,f32> for f32 {
|
||||
fn mul(&self, other: &f32) -> f32 { *self * *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Div<f32,f32> for f32 {
|
||||
fn div(&self, other: &f32) -> f32 { *self / *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Modulo<f32,f32> for f32 {
|
||||
fn modulo(&self, other: &f32) -> f32 { *self % *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Neg<f32> for f32 {
|
||||
fn neg(&self) -> f32 { -*self }
|
||||
}
|
||||
|
||||
impl num::Round for f32 {
|
||||
#[inline(always)]
|
||||
fn round(&self, mode: num::RoundMode) -> f32 {
|
||||
match mode {
|
||||
num::RoundDown => floor(*self),
|
||||
num::RoundUp => ceil(*self),
|
||||
num::RoundToZero if is_negative(*self) => ceil(*self),
|
||||
num::RoundToZero => floor(*self),
|
||||
num::RoundFromZero if is_negative(*self) => floor(*self),
|
||||
num::RoundFromZero => ceil(*self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn floor(&self) -> f32 { floor(*self) }
|
||||
#[inline(always)]
|
||||
fn ceil(&self) -> f32 { ceil(*self) }
|
||||
#[inline(always)]
|
||||
fn fract(&self) -> f32 {
|
||||
if is_negative(*self) {
|
||||
(*self) - ceil(*self)
|
||||
} else {
|
||||
(*self) - floor(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Section: String Conversions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a float to a string
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str(num: f32) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in hexadecimal format
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_hex(num: f32) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*
|
||||
* # Failure
|
||||
*
|
||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
||||
* possible misinterpretation of the result at higher bases. If those values
|
||||
* are expected, use `to_str_radix_special()` instead.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix(num: f32, rdx: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix, and a flag indicating
|
||||
* whether it's a special value
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with exactly the number of
|
||||
* provided significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_exact(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with a maximum number of
|
||||
* significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_digits(num: f32, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
impl to_str::ToStr for f32 {
|
||||
#[inline(always)]
|
||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
||||
}
|
||||
|
||||
impl num::ToStrRadix for f32 {
|
||||
#[inline(always)]
|
||||
fn to_str_radix(&self, rdx: uint) -> ~str {
|
||||
to_str_radix(*self, rdx)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 10 to a float.
|
||||
* Accepts a optional decimal exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * '3.14'
|
||||
* * '+3.14', equivalent to '3.14'
|
||||
* * '-3.14'
|
||||
* * '2.5E10', or equivalently, '2.5e10'
|
||||
* * '2.5E-10'
|
||||
* * '.' (understood as 0)
|
||||
* * '5.'
|
||||
* * '.5', or, equivalently, '0.5'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str(num: &str) -> Option<f32> {
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 16 to a float.
|
||||
* Accepts a optional binary exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * 'a4.fe'
|
||||
* * '+a4.fe', equivalent to 'a4.fe'
|
||||
* * '-a4.fe'
|
||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
||||
* * '2b.aP-128'
|
||||
* * '.' (understood as 0)
|
||||
* * 'c.'
|
||||
* * '.c', or, equivalently, '0.c'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_hex(num: &str) -> Option<f32> {
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in an given base to a float.
|
||||
*
|
||||
* Due to possible conflicts, this function does **not** accept
|
||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
||||
* does it recognize exponents of any kind.
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
|
||||
strconv::from_str_common(num, rdx, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for f32 {
|
||||
#[inline(always)]
|
||||
fn from_str(val: &str) -> Option<f32> { from_str(val) }
|
||||
}
|
||||
|
||||
impl num::FromStrRadix for f32 {
|
||||
#[inline(always)]
|
||||
fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
|
||||
from_str_radix(val, rdx)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_num() {
|
||||
let ten: f32 = num::cast(10);
|
||||
let two: f32 = num::cast(2);
|
||||
|
||||
assert!((ten.add(&two) == num::cast(12)));
|
||||
assert!((ten.sub(&two) == num::cast(8)));
|
||||
assert!((ten.mul(&two) == num::cast(20)));
|
||||
assert!((ten.div(&two) == num::cast(5)));
|
||||
assert!((ten.modulo(&two) == num::cast(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numcast() {
|
||||
assert!((20u == 20f32.to_uint()));
|
||||
assert!((20u8 == 20f32.to_u8()));
|
||||
assert!((20u16 == 20f32.to_u16()));
|
||||
assert!((20u32 == 20f32.to_u32()));
|
||||
assert!((20u64 == 20f32.to_u64()));
|
||||
assert!((20i == 20f32.to_int()));
|
||||
assert!((20i8 == 20f32.to_i8()));
|
||||
assert!((20i16 == 20f32.to_i16()));
|
||||
assert!((20i32 == 20f32.to_i32()));
|
||||
assert!((20i64 == 20f32.to_i64()));
|
||||
assert!((20f == 20f32.to_float()));
|
||||
assert!((20f32 == 20f32.to_f32()));
|
||||
assert!((20f64 == 20f32.to_f64()));
|
||||
|
||||
assert!((20f32 == NumCast::from(20u)));
|
||||
assert!((20f32 == NumCast::from(20u8)));
|
||||
assert!((20f32 == NumCast::from(20u16)));
|
||||
assert!((20f32 == NumCast::from(20u32)));
|
||||
assert!((20f32 == NumCast::from(20u64)));
|
||||
assert!((20f32 == NumCast::from(20i)));
|
||||
assert!((20f32 == NumCast::from(20i8)));
|
||||
assert!((20f32 == NumCast::from(20i16)));
|
||||
assert!((20f32 == NumCast::from(20i32)));
|
||||
assert!((20f32 == NumCast::from(20i64)));
|
||||
assert!((20f32 == NumCast::from(20f)));
|
||||
assert!((20f32 == NumCast::from(20f32)));
|
||||
assert!((20f32 == NumCast::from(20f64)));
|
||||
|
||||
assert!((20f32 == num::cast(20u)));
|
||||
assert!((20f32 == num::cast(20u8)));
|
||||
assert!((20f32 == num::cast(20u16)));
|
||||
assert!((20f32 == num::cast(20u32)));
|
||||
assert!((20f32 == num::cast(20u64)));
|
||||
assert!((20f32 == num::cast(20i)));
|
||||
assert!((20f32 == num::cast(20i8)));
|
||||
assert!((20f32 == num::cast(20i16)));
|
||||
assert!((20f32 == num::cast(20i32)));
|
||||
assert!((20f32 == num::cast(20i64)));
|
||||
assert!((20f32 == num::cast(20f)));
|
||||
assert!((20f32 == num::cast(20f32)));
|
||||
assert!((20f32 == num::cast(20f64)));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
@ -1,670 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations and constants for `f64`
|
||||
|
||||
use cmath;
|
||||
use libc::{c_double, c_int};
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use option::Option;
|
||||
use unstable::intrinsics::floorf64;
|
||||
use to_str;
|
||||
use from_str;
|
||||
|
||||
#[cfg(notest)] use cmp;
|
||||
#[cfg(notest)] use ops;
|
||||
|
||||
pub use cmath::c_double_targ_consts::*;
|
||||
pub use cmp::{min, max};
|
||||
|
||||
macro_rules! delegate(
|
||||
(
|
||||
fn $name:ident(
|
||||
$(
|
||||
$arg:ident : $arg_ty:ty
|
||||
),*
|
||||
) -> $rv:ty = $bound_name:path
|
||||
) => (
|
||||
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
|
||||
unsafe {
|
||||
$bound_name($( $arg ),*)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
delegate!(fn acos(n: c_double) -> c_double = cmath::c_double_utils::acos)
|
||||
delegate!(fn asin(n: c_double) -> c_double = cmath::c_double_utils::asin)
|
||||
delegate!(fn atan(n: c_double) -> c_double = cmath::c_double_utils::atan)
|
||||
delegate!(fn atan2(a: c_double, b: c_double) -> c_double =
|
||||
cmath::c_double_utils::atan2)
|
||||
delegate!(fn cbrt(n: c_double) -> c_double = cmath::c_double_utils::cbrt)
|
||||
delegate!(fn ceil(n: c_double) -> c_double = cmath::c_double_utils::ceil)
|
||||
delegate!(fn copysign(x: c_double, y: c_double) -> c_double =
|
||||
cmath::c_double_utils::copysign)
|
||||
delegate!(fn cos(n: c_double) -> c_double = cmath::c_double_utils::cos)
|
||||
delegate!(fn cosh(n: c_double) -> c_double = cmath::c_double_utils::cosh)
|
||||
delegate!(fn erf(n: c_double) -> c_double = cmath::c_double_utils::erf)
|
||||
delegate!(fn erfc(n: c_double) -> c_double = cmath::c_double_utils::erfc)
|
||||
delegate!(fn exp(n: c_double) -> c_double = cmath::c_double_utils::exp)
|
||||
delegate!(fn expm1(n: c_double) -> c_double = cmath::c_double_utils::expm1)
|
||||
delegate!(fn exp2(n: c_double) -> c_double = cmath::c_double_utils::exp2)
|
||||
delegate!(fn abs(n: c_double) -> c_double = cmath::c_double_utils::abs)
|
||||
delegate!(fn abs_sub(a: c_double, b: c_double) -> c_double =
|
||||
cmath::c_double_utils::abs_sub)
|
||||
delegate!(fn mul_add(a: c_double, b: c_double, c: c_double) -> c_double =
|
||||
cmath::c_double_utils::mul_add)
|
||||
delegate!(fn fmax(a: c_double, b: c_double) -> c_double =
|
||||
cmath::c_double_utils::fmax)
|
||||
delegate!(fn fmin(a: c_double, b: c_double) -> c_double =
|
||||
cmath::c_double_utils::fmin)
|
||||
delegate!(fn nextafter(x: c_double, y: c_double) -> c_double =
|
||||
cmath::c_double_utils::nextafter)
|
||||
delegate!(fn frexp(n: c_double, value: &mut c_int) -> c_double =
|
||||
cmath::c_double_utils::frexp)
|
||||
delegate!(fn hypot(x: c_double, y: c_double) -> c_double =
|
||||
cmath::c_double_utils::hypot)
|
||||
delegate!(fn ldexp(x: c_double, n: c_int) -> c_double =
|
||||
cmath::c_double_utils::ldexp)
|
||||
delegate!(fn lgamma(n: c_double, sign: &mut c_int) -> c_double =
|
||||
cmath::c_double_utils::lgamma)
|
||||
delegate!(fn ln(n: c_double) -> c_double = cmath::c_double_utils::ln)
|
||||
delegate!(fn log_radix(n: c_double) -> c_double =
|
||||
cmath::c_double_utils::log_radix)
|
||||
delegate!(fn ln1p(n: c_double) -> c_double = cmath::c_double_utils::ln1p)
|
||||
delegate!(fn log10(n: c_double) -> c_double = cmath::c_double_utils::log10)
|
||||
delegate!(fn log2(n: c_double) -> c_double = cmath::c_double_utils::log2)
|
||||
delegate!(fn ilog_radix(n: c_double) -> c_int =
|
||||
cmath::c_double_utils::ilog_radix)
|
||||
delegate!(fn modf(n: c_double, iptr: &mut c_double) -> c_double =
|
||||
cmath::c_double_utils::modf)
|
||||
delegate!(fn pow(n: c_double, e: c_double) -> c_double =
|
||||
cmath::c_double_utils::pow)
|
||||
delegate!(fn round(n: c_double) -> c_double = cmath::c_double_utils::round)
|
||||
delegate!(fn ldexp_radix(n: c_double, i: c_int) -> c_double =
|
||||
cmath::c_double_utils::ldexp_radix)
|
||||
delegate!(fn sin(n: c_double) -> c_double = cmath::c_double_utils::sin)
|
||||
delegate!(fn sinh(n: c_double) -> c_double = cmath::c_double_utils::sinh)
|
||||
delegate!(fn sqrt(n: c_double) -> c_double = cmath::c_double_utils::sqrt)
|
||||
delegate!(fn tan(n: c_double) -> c_double = cmath::c_double_utils::tan)
|
||||
delegate!(fn tanh(n: c_double) -> c_double = cmath::c_double_utils::tanh)
|
||||
delegate!(fn tgamma(n: c_double) -> c_double = cmath::c_double_utils::tgamma)
|
||||
delegate!(fn trunc(n: c_double) -> c_double = cmath::c_double_utils::trunc)
|
||||
delegate!(fn j0(n: c_double) -> c_double = cmath::c_double_utils::j0)
|
||||
delegate!(fn j1(n: c_double) -> c_double = cmath::c_double_utils::j1)
|
||||
delegate!(fn jn(i: c_int, n: c_double) -> c_double =
|
||||
cmath::c_double_utils::jn)
|
||||
delegate!(fn y0(n: c_double) -> c_double = cmath::c_double_utils::y0)
|
||||
delegate!(fn y1(n: c_double) -> c_double = cmath::c_double_utils::y1)
|
||||
delegate!(fn yn(i: c_int, n: c_double) -> c_double =
|
||||
cmath::c_double_utils::yn)
|
||||
|
||||
// FIXME (#1433): obtain these in a different way
|
||||
|
||||
// These are not defined inside consts:: for consistency with
|
||||
// the integer types
|
||||
|
||||
pub static radix: uint = 2u;
|
||||
|
||||
pub static mantissa_digits: uint = 53u;
|
||||
pub static digits: uint = 15u;
|
||||
|
||||
pub static epsilon: f64 = 2.2204460492503131e-16_f64;
|
||||
|
||||
pub static min_value: f64 = 2.2250738585072014e-308_f64;
|
||||
pub static max_value: f64 = 1.7976931348623157e+308_f64;
|
||||
|
||||
pub static min_exp: int = -1021;
|
||||
pub static max_exp: int = 1024;
|
||||
|
||||
pub static min_10_exp: int = -307;
|
||||
pub static max_10_exp: int = 308;
|
||||
|
||||
pub static NaN: f64 = 0.0_f64/0.0_f64;
|
||||
|
||||
pub static infinity: f64 = 1.0_f64/0.0_f64;
|
||||
|
||||
pub static neg_infinity: f64 = -1.0_f64/0.0_f64;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_NaN(f: f64) -> bool { f != f }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add(x: f64, y: f64) -> f64 { return x + y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub(x: f64, y: f64) -> f64 { return x - y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul(x: f64, y: f64) -> f64 { return x * y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn div(x: f64, y: f64) -> f64 { return x / y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn rem(x: f64, y: f64) -> f64 { return x % y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lt(x: f64, y: f64) -> bool { return x < y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn le(x: f64, y: f64) -> bool { return x <= y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn eq(x: f64, y: f64) -> bool { return x == y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ne(x: f64, y: f64) -> bool { return x != y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ge(x: f64, y: f64) -> bool { return x >= y; }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn gt(x: f64, y: f64) -> bool { return x > y; }
|
||||
|
||||
/// Returns true if `x` is a positive number, including +0.0f640 and +Infinity
|
||||
#[inline(always)]
|
||||
pub fn is_positive(x: f64) -> bool
|
||||
{ return x > 0.0f64 || (1.0f64/x) == infinity; }
|
||||
|
||||
/// Returns true if `x` is a negative number, including -0.0f640 and -Infinity
|
||||
#[inline(always)]
|
||||
pub fn is_negative(x: f64) -> bool
|
||||
{ return x < 0.0f64 || (1.0f64/x) == neg_infinity; }
|
||||
|
||||
/**
|
||||
* Returns true if `x` is a negative number, including -0.0f640 and -Infinity
|
||||
*
|
||||
* This is the same as `f64::is_negative`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_nonpositive(x: f64) -> bool {
|
||||
return x < 0.0f64 || (1.0f64/x) == neg_infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `x` is a positive number, including +0.0f640 and +Infinity
|
||||
*
|
||||
* This is the same as `f64::positive`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn is_nonnegative(x: f64) -> bool {
|
||||
return x > 0.0f64 || (1.0f64/x) == infinity;
|
||||
}
|
||||
|
||||
/// Returns true if `x` is a zero number (positive or negative zero)
|
||||
#[inline(always)]
|
||||
pub fn is_zero(x: f64) -> bool {
|
||||
return x == 0.0f64 || x == -0.0f64;
|
||||
}
|
||||
|
||||
/// Returns true if `x`is an infinite number
|
||||
#[inline(always)]
|
||||
pub fn is_infinite(x: f64) -> bool {
|
||||
return x == infinity || x == neg_infinity;
|
||||
}
|
||||
|
||||
/// Returns true if `x` is a finite number
|
||||
#[inline(always)]
|
||||
pub fn is_finite(x: f64) -> bool {
|
||||
return !(is_NaN(x) || is_infinite(x));
|
||||
}
|
||||
|
||||
/// Returns `x` rounded down
|
||||
#[inline(always)]
|
||||
pub fn floor(x: f64) -> f64 { unsafe { floorf64(x) } }
|
||||
|
||||
// FIXME (#1999): add is_normal, is_subnormal, and fpclassify
|
||||
|
||||
/* Module: consts */
|
||||
pub mod consts {
|
||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
||||
// constants from cmath.
|
||||
/// Archimedes' constant
|
||||
pub static pi: f64 = 3.14159265358979323846264338327950288_f64;
|
||||
|
||||
/// pi/2.0
|
||||
pub static frac_pi_2: f64 = 1.57079632679489661923132169163975144_f64;
|
||||
|
||||
/// pi/4.0
|
||||
pub static frac_pi_4: f64 = 0.785398163397448309615660845819875721_f64;
|
||||
|
||||
/// 1.0/pi
|
||||
pub static frac_1_pi: f64 = 0.318309886183790671537767526745028724_f64;
|
||||
|
||||
/// 2.0/pi
|
||||
pub static frac_2_pi: f64 = 0.636619772367581343075535053490057448_f64;
|
||||
|
||||
/// 2.0/sqrt(pi)
|
||||
pub static frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517_f64;
|
||||
|
||||
/// sqrt(2.0)
|
||||
pub static sqrt2: f64 = 1.41421356237309504880168872420969808_f64;
|
||||
|
||||
/// 1.0/sqrt(2.0)
|
||||
pub static frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039_f64;
|
||||
|
||||
/// Euler's number
|
||||
pub static e: f64 = 2.71828182845904523536028747135266250_f64;
|
||||
|
||||
/// log2(e)
|
||||
pub static log2_e: f64 = 1.44269504088896340735992468100189214_f64;
|
||||
|
||||
/// log10(e)
|
||||
pub static log10_e: f64 = 0.434294481903251827651128918916605082_f64;
|
||||
|
||||
/// ln(2.0)
|
||||
pub static ln_2: f64 = 0.693147180559945309417232121458176568_f64;
|
||||
|
||||
/// ln(10.0)
|
||||
pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn signbit(x: f64) -> int {
|
||||
if is_negative(x) { return 1; } else { return 0; }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn logarithm(n: f64, b: f64) -> f64 {
|
||||
return log2(n) / log2(b);
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl cmp::Eq for f64 {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &f64) -> bool { (*self) == (*other) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &f64) -> bool { (*self) != (*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl cmp::Ord for f64 {
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &f64) -> bool { (*self) < (*other) }
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &f64) -> bool { (*self) <= (*other) }
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &f64) -> bool { (*self) >= (*other) }
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &f64) -> bool { (*self) > (*other) }
|
||||
}
|
||||
|
||||
impl NumCast for f64 {
|
||||
/**
|
||||
* Cast `n` to an `f64`
|
||||
*/
|
||||
#[inline(always)]
|
||||
fn from<N:NumCast>(n: N) -> f64 { n.to_f64() }
|
||||
|
||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
||||
|
||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
||||
|
||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
||||
#[inline(always)] fn to_f64(&self) -> f64 { *self }
|
||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
||||
}
|
||||
|
||||
impl num::Zero for f64 {
|
||||
#[inline(always)]
|
||||
fn zero() -> f64 { 0.0 }
|
||||
}
|
||||
|
||||
impl num::One for f64 {
|
||||
#[inline(always)]
|
||||
fn one() -> f64 { 1.0 }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<f64,f64> for f64 {
|
||||
fn add(&self, other: &f64) -> f64 { *self + *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Sub<f64,f64> for f64 {
|
||||
fn sub(&self, other: &f64) -> f64 { *self - *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Mul<f64,f64> for f64 {
|
||||
fn mul(&self, other: &f64) -> f64 { *self * *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Div<f64,f64> for f64 {
|
||||
fn div(&self, other: &f64) -> f64 { *self / *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Modulo<f64,f64> for f64 {
|
||||
fn modulo(&self, other: &f64) -> f64 { *self % *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Neg<f64> for f64 {
|
||||
fn neg(&self) -> f64 { -*self }
|
||||
}
|
||||
|
||||
impl num::Round for f64 {
|
||||
#[inline(always)]
|
||||
fn round(&self, mode: num::RoundMode) -> f64 {
|
||||
match mode {
|
||||
num::RoundDown => floor(*self),
|
||||
num::RoundUp => ceil(*self),
|
||||
num::RoundToZero if is_negative(*self) => ceil(*self),
|
||||
num::RoundToZero => floor(*self),
|
||||
num::RoundFromZero if is_negative(*self) => floor(*self),
|
||||
num::RoundFromZero => ceil(*self)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn floor(&self) -> f64 { floor(*self) }
|
||||
#[inline(always)]
|
||||
fn ceil(&self) -> f64 { ceil(*self) }
|
||||
#[inline(always)]
|
||||
fn fract(&self) -> f64 {
|
||||
if is_negative(*self) {
|
||||
(*self) - ceil(*self)
|
||||
} else {
|
||||
(*self) - floor(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Section: String Conversions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a float to a string
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str(num: f64) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in hexadecimal format
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_hex(num: f64) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*
|
||||
* # Failure
|
||||
*
|
||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
||||
* possible misinterpretation of the result at higher bases. If those values
|
||||
* are expected, use `to_str_radix_special()` instead.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix(num: f64, rdx: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, rdx, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix, and a flag indicating
|
||||
* whether it's a special value
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, rdx, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with exactly the number of
|
||||
* provided significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_exact(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with a maximum number of
|
||||
* significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_digits(num: f64, dig: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
|
||||
r
|
||||
}
|
||||
|
||||
impl to_str::ToStr for f64 {
|
||||
#[inline(always)]
|
||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
||||
}
|
||||
|
||||
impl num::ToStrRadix for f64 {
|
||||
#[inline(always)]
|
||||
fn to_str_radix(&self, rdx: uint) -> ~str {
|
||||
to_str_radix(*self, rdx)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 10 to a float.
|
||||
* Accepts a optional decimal exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * '3.14'
|
||||
* * '+3.14', equivalent to '3.14'
|
||||
* * '-3.14'
|
||||
* * '2.5E10', or equivalently, '2.5e10'
|
||||
* * '2.5E-10'
|
||||
* * '.' (understood as 0)
|
||||
* * '5.'
|
||||
* * '.5', or, equivalently, '0.5'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str(num: &str) -> Option<f64> {
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 16 to a float.
|
||||
* Accepts a optional binary exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * 'a4.fe'
|
||||
* * '+a4.fe', equivalent to 'a4.fe'
|
||||
* * '-a4.fe'
|
||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
||||
* * '2b.aP-128'
|
||||
* * '.' (understood as 0)
|
||||
* * 'c.'
|
||||
* * '.c', or, equivalently, '0.c'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_hex(num: &str) -> Option<f64> {
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in an given base to a float.
|
||||
*
|
||||
* Due to possible conflicts, this function does **not** accept
|
||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
||||
* does it recognize exponents of any kind.
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
|
||||
strconv::from_str_common(num, rdx, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for f64 {
|
||||
#[inline(always)]
|
||||
fn from_str(val: &str) -> Option<f64> { from_str(val) }
|
||||
}
|
||||
|
||||
impl num::FromStrRadix for f64 {
|
||||
#[inline(always)]
|
||||
fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
|
||||
from_str_radix(val, rdx)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_num() {
|
||||
let ten: f64 = num::cast(10);
|
||||
let two: f64 = num::cast(2);
|
||||
|
||||
assert!((ten.add(&two) == num::cast(12)));
|
||||
assert!((ten.sub(&two) == num::cast(8)));
|
||||
assert!((ten.mul(&two) == num::cast(20)));
|
||||
assert!((ten.div(&two) == num::cast(5)));
|
||||
assert!((ten.modulo(&two) == num::cast(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numcast() {
|
||||
assert!((20u == 20f64.to_uint()));
|
||||
assert!((20u8 == 20f64.to_u8()));
|
||||
assert!((20u16 == 20f64.to_u16()));
|
||||
assert!((20u32 == 20f64.to_u32()));
|
||||
assert!((20u64 == 20f64.to_u64()));
|
||||
assert!((20i == 20f64.to_int()));
|
||||
assert!((20i8 == 20f64.to_i8()));
|
||||
assert!((20i16 == 20f64.to_i16()));
|
||||
assert!((20i32 == 20f64.to_i32()));
|
||||
assert!((20i64 == 20f64.to_i64()));
|
||||
assert!((20f == 20f64.to_float()));
|
||||
assert!((20f32 == 20f64.to_f32()));
|
||||
assert!((20f64 == 20f64.to_f64()));
|
||||
|
||||
assert!((20f64 == NumCast::from(20u)));
|
||||
assert!((20f64 == NumCast::from(20u8)));
|
||||
assert!((20f64 == NumCast::from(20u16)));
|
||||
assert!((20f64 == NumCast::from(20u32)));
|
||||
assert!((20f64 == NumCast::from(20u64)));
|
||||
assert!((20f64 == NumCast::from(20i)));
|
||||
assert!((20f64 == NumCast::from(20i8)));
|
||||
assert!((20f64 == NumCast::from(20i16)));
|
||||
assert!((20f64 == NumCast::from(20i32)));
|
||||
assert!((20f64 == NumCast::from(20i64)));
|
||||
assert!((20f64 == NumCast::from(20f)));
|
||||
assert!((20f64 == NumCast::from(20f32)));
|
||||
assert!((20f64 == NumCast::from(20f64)));
|
||||
|
||||
assert!((20f64 == num::cast(20u)));
|
||||
assert!((20f64 == num::cast(20u8)));
|
||||
assert!((20f64 == num::cast(20u16)));
|
||||
assert!((20f64 == num::cast(20u32)));
|
||||
assert!((20f64 == num::cast(20u64)));
|
||||
assert!((20f64 == num::cast(20i)));
|
||||
assert!((20f64 == num::cast(20i8)));
|
||||
assert!((20f64 == num::cast(20i16)));
|
||||
assert!((20f64 == num::cast(20i32)));
|
||||
assert!((20f64 == num::cast(20i64)));
|
||||
assert!((20f64 == num::cast(20f)));
|
||||
assert!((20f64 == num::cast(20f32)));
|
||||
assert!((20f64 == num::cast(20f64)));
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
@ -1,757 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations and constants for `float`
|
||||
|
||||
// Even though this module exports everything defined in it,
|
||||
// because it contains re-exports, we also have to explicitly
|
||||
// export locally defined things. That's a bit annoying.
|
||||
|
||||
|
||||
// export when m_float == c_double
|
||||
|
||||
|
||||
// PORT this must match in width according to architecture
|
||||
|
||||
use f64;
|
||||
use num::NumCast;
|
||||
use num::strconv;
|
||||
use num;
|
||||
use option::Option;
|
||||
use to_str;
|
||||
use from_str;
|
||||
|
||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
||||
#[cfg(notest)] use ops;
|
||||
#[cfg(test)] use option::{Some, None};
|
||||
|
||||
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
|
||||
pub use f64::logarithm;
|
||||
pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor};
|
||||
pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub};
|
||||
pub use f64::{mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp};
|
||||
pub use f64::{lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix};
|
||||
pub use f64::{modf, pow, round, sinh, tanh, tgamma, trunc};
|
||||
pub use f64::signbit;
|
||||
pub use f64::{j0, j1, jn, y0, y1, yn};
|
||||
|
||||
pub static NaN: float = 0.0/0.0;
|
||||
|
||||
pub static infinity: float = 1.0/0.0;
|
||||
|
||||
pub static neg_infinity: float = -1.0/0.0;
|
||||
|
||||
/* Module: consts */
|
||||
pub mod consts {
|
||||
// FIXME (requires Issue #1433 to fix): replace with mathematical
|
||||
// staticants from cmath.
|
||||
/// Archimedes' staticant
|
||||
pub static pi: float = 3.14159265358979323846264338327950288;
|
||||
|
||||
/// pi/2.0
|
||||
pub static frac_pi_2: float = 1.57079632679489661923132169163975144;
|
||||
|
||||
/// pi/4.0
|
||||
pub static frac_pi_4: float = 0.785398163397448309615660845819875721;
|
||||
|
||||
/// 1.0/pi
|
||||
pub static frac_1_pi: float = 0.318309886183790671537767526745028724;
|
||||
|
||||
/// 2.0/pi
|
||||
pub static frac_2_pi: float = 0.636619772367581343075535053490057448;
|
||||
|
||||
/// 2.0/sqrt(pi)
|
||||
pub static frac_2_sqrtpi: float = 1.12837916709551257389615890312154517;
|
||||
|
||||
/// sqrt(2.0)
|
||||
pub static sqrt2: float = 1.41421356237309504880168872420969808;
|
||||
|
||||
/// 1.0/sqrt(2.0)
|
||||
pub static frac_1_sqrt2: float = 0.707106781186547524400844362104849039;
|
||||
|
||||
/// Euler's number
|
||||
pub static e: float = 2.71828182845904523536028747135266250;
|
||||
|
||||
/// log2(e)
|
||||
pub static log2_e: float = 1.44269504088896340735992468100189214;
|
||||
|
||||
/// log10(e)
|
||||
pub static log10_e: float = 0.434294481903251827651128918916605082;
|
||||
|
||||
/// ln(2.0)
|
||||
pub static ln_2: float = 0.693147180559945309417232121458176568;
|
||||
|
||||
/// ln(10.0)
|
||||
pub static ln_10: float = 2.30258509299404568401799145468436421;
|
||||
}
|
||||
|
||||
/*
|
||||
* Section: String Conversions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a float to a string
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str(num: float) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in hexadecimal format
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_hex(num: float) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 16u, true, strconv::SignNeg, strconv::DigAll);
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*
|
||||
* # Failure
|
||||
*
|
||||
* Fails if called on a special value like `inf`, `-inf` or `NaN` due to
|
||||
* possible misinterpretation of the result at higher bases. If those values
|
||||
* are expected, use `to_str_radix_special()` instead.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix(num: float, radix: uint) -> ~str {
|
||||
let (r, special) = strconv::to_str_common(
|
||||
&num, radix, true, strconv::SignNeg, strconv::DigAll);
|
||||
if special { fail!(~"number has a special value, \
|
||||
try to_str_radix_special() if those are expected") }
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string in a given radix, and a flag indicating
|
||||
* whether it's a special value
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * radix - The base to use
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
|
||||
strconv::to_str_common(&num, radix, true,
|
||||
strconv::SignNeg, strconv::DigAll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with exactly the number of
|
||||
* provided significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_exact(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigExact(digits));
|
||||
r
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_exact_do_decimal() {
|
||||
let s = to_str_exact(5.0, 4u);
|
||||
assert!(s == ~"5.0000");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float to a string with a maximum number of
|
||||
* significant digits
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - The float value
|
||||
* * digits - The number of significant digits
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_str_digits(num: float, digits: uint) -> ~str {
|
||||
let (r, _) = strconv::to_str_common(
|
||||
&num, 10u, true, strconv::SignNeg, strconv::DigMax(digits));
|
||||
r
|
||||
}
|
||||
|
||||
impl to_str::ToStr for float {
|
||||
#[inline(always)]
|
||||
fn to_str(&self) -> ~str { to_str_digits(*self, 8) }
|
||||
}
|
||||
|
||||
impl num::ToStrRadix for float {
|
||||
#[inline(always)]
|
||||
fn to_str_radix(&self, radix: uint) -> ~str {
|
||||
to_str_radix(*self, radix)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 10 to a float.
|
||||
* Accepts a optional decimal exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * '3.14'
|
||||
* * '+3.14', equivalent to '3.14'
|
||||
* * '-3.14'
|
||||
* * '2.5E10', or equivalently, '2.5e10'
|
||||
* * '2.5E-10'
|
||||
* * '.' (understood as 0)
|
||||
* * '5.'
|
||||
* * '.5', or, equivalently, '0.5'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str(num: &str) -> Option<float> {
|
||||
strconv::from_str_common(num, 10u, true, true, true,
|
||||
strconv::ExpDec, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in base 16 to a float.
|
||||
* Accepts a optional binary exponent.
|
||||
*
|
||||
* This function accepts strings such as
|
||||
*
|
||||
* * 'a4.fe'
|
||||
* * '+a4.fe', equivalent to 'a4.fe'
|
||||
* * '-a4.fe'
|
||||
* * '2b.aP128', or equivalently, '2b.ap128'
|
||||
* * '2b.aP-128'
|
||||
* * '.' (understood as 0)
|
||||
* * 'c.'
|
||||
* * '.c', or, equivalently, '0.c'
|
||||
* * '+inf', 'inf', '-inf', 'NaN'
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `[num]`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_hex(num: &str) -> Option<float> {
|
||||
strconv::from_str_common(num, 16u, true, true, true,
|
||||
strconv::ExpBin, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string in an given base to a float.
|
||||
*
|
||||
* Due to possible conflicts, this function does **not** accept
|
||||
* the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
|
||||
* does it recognize exponents of any kind.
|
||||
*
|
||||
* Leading and trailing whitespace represent an error.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * num - A string
|
||||
* * radix - The base to use. Must lie in the range [2 .. 36]
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `none` if the string did not represent a valid number. Otherwise,
|
||||
* `Some(n)` where `n` is the floating-point number represented by `num`.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
|
||||
strconv::from_str_common(num, radix, true, true, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl from_str::FromStr for float {
|
||||
#[inline(always)]
|
||||
fn from_str(val: &str) -> Option<float> { from_str(val) }
|
||||
}
|
||||
|
||||
impl num::FromStrRadix for float {
|
||||
#[inline(always)]
|
||||
fn from_str_radix(val: &str, radix: uint) -> Option<float> {
|
||||
from_str_radix(val, radix)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Section: Arithmetics
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compute the exponentiation of an integer by another integer as a float
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * x - The base
|
||||
* * pow - The exponent
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
|
||||
*/
|
||||
pub fn pow_with_uint(base: uint, pow: uint) -> float {
|
||||
if base == 0u {
|
||||
if pow == 0u {
|
||||
return NaN as float;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
let mut my_pow = pow;
|
||||
let mut total = 1f;
|
||||
let mut multiplier = base as float;
|
||||
while (my_pow > 0u) {
|
||||
if my_pow % 2u == 1u {
|
||||
total = total * multiplier;
|
||||
}
|
||||
my_pow /= 2u;
|
||||
multiplier *= multiplier;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
|
||||
#[inline(always)]
|
||||
pub fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn abs(x: float) -> float {
|
||||
unsafe { f64::abs(x as f64) as float }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn sqrt(x: float) -> float {
|
||||
unsafe { f64::sqrt(x as f64) as float }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn atan(x: float) -> float {
|
||||
unsafe { f64::atan(x as f64) as float }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn sin(x: float) -> float {
|
||||
unsafe { f64::sin(x as f64) as float }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn cos(x: float) -> float {
|
||||
unsafe { f64::cos(x as f64) as float }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn tan(x: float) -> float {
|
||||
unsafe { f64::tan(x as f64) as float }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Eq for float {
|
||||
fn eq(&self, other: &float) -> bool { (*self) == (*other) }
|
||||
fn ne(&self, other: &float) -> bool { (*self) != (*other) }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Ord for float {
|
||||
fn lt(&self, other: &float) -> bool { (*self) < (*other) }
|
||||
fn le(&self, other: &float) -> bool { (*self) <= (*other) }
|
||||
fn ge(&self, other: &float) -> bool { (*self) >= (*other) }
|
||||
fn gt(&self, other: &float) -> bool { (*self) > (*other) }
|
||||
}
|
||||
|
||||
impl num::Zero for float {
|
||||
#[inline(always)]
|
||||
fn zero() -> float { 0.0 }
|
||||
}
|
||||
|
||||
impl num::One for float {
|
||||
#[inline(always)]
|
||||
fn one() -> float { 1.0 }
|
||||
}
|
||||
|
||||
impl NumCast for float {
|
||||
/**
|
||||
* Cast `n` to a `float`
|
||||
*/
|
||||
#[inline(always)]
|
||||
fn from<N:NumCast>(n: N) -> float { n.to_float() }
|
||||
|
||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
||||
|
||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
||||
|
||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
||||
#[inline(always)] fn to_float(&self) -> float { *self }
|
||||
}
|
||||
|
||||
impl num::Round for float {
|
||||
#[inline(always)]
|
||||
fn round(&self, mode: num::RoundMode) -> float {
|
||||
match mode {
|
||||
num::RoundDown
|
||||
=> f64::floor(*self as f64) as float,
|
||||
num::RoundUp
|
||||
=> f64::ceil(*self as f64) as float,
|
||||
num::RoundToZero if is_negative(*self)
|
||||
=> f64::ceil(*self as f64) as float,
|
||||
num::RoundToZero
|
||||
=> f64::floor(*self as f64) as float,
|
||||
num::RoundFromZero if is_negative(*self)
|
||||
=> f64::floor(*self as f64) as float,
|
||||
num::RoundFromZero
|
||||
=> f64::ceil(*self as f64) as float
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn floor(&self) -> float { f64::floor(*self as f64) as float}
|
||||
#[inline(always)]
|
||||
fn ceil(&self) -> float { f64::ceil(*self as f64) as float}
|
||||
#[inline(always)]
|
||||
fn fract(&self) -> float {
|
||||
if is_negative(*self) {
|
||||
(*self) - (f64::ceil(*self as f64) as float)
|
||||
} else {
|
||||
(*self) - (f64::floor(*self as f64) as float)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<float,float> for float {
|
||||
fn add(&self, other: &float) -> float { *self + *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Sub<float,float> for float {
|
||||
fn sub(&self, other: &float) -> float { *self - *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Mul<float,float> for float {
|
||||
fn mul(&self, other: &float) -> float { *self * *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Div<float,float> for float {
|
||||
fn div(&self, other: &float) -> float { *self / *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Modulo<float,float> for float {
|
||||
fn modulo(&self, other: &float) -> float { *self % *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Neg<float> for float {
|
||||
fn neg(&self) -> float { -*self }
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_from_str() {
|
||||
assert!(from_str(~"3") == Some(3.));
|
||||
assert!(from_str(~"3.14") == Some(3.14));
|
||||
assert!(from_str(~"+3.14") == Some(3.14));
|
||||
assert!(from_str(~"-3.14") == Some(-3.14));
|
||||
assert!(from_str(~"2.5E10") == Some(25000000000.));
|
||||
assert!(from_str(~"2.5e10") == Some(25000000000.));
|
||||
assert!(from_str(~"25000000000.E-10") == Some(2.5));
|
||||
assert!(from_str(~".") == Some(0.));
|
||||
assert!(from_str(~".e1") == Some(0.));
|
||||
assert!(from_str(~".e-1") == Some(0.));
|
||||
assert!(from_str(~"5.") == Some(5.));
|
||||
assert!(from_str(~".5") == Some(0.5));
|
||||
assert!(from_str(~"0.5") == Some(0.5));
|
||||
assert!(from_str(~"-.5") == Some(-0.5));
|
||||
assert!(from_str(~"-5") == Some(-5.));
|
||||
assert!(from_str(~"inf") == Some(infinity));
|
||||
assert!(from_str(~"+inf") == Some(infinity));
|
||||
assert!(from_str(~"-inf") == Some(neg_infinity));
|
||||
// note: NaN != NaN, hence this slightly complex test
|
||||
match from_str(~"NaN") {
|
||||
Some(f) => assert!(is_NaN(f)),
|
||||
None => fail!()
|
||||
}
|
||||
// note: -0 == 0, hence these slightly more complex tests
|
||||
match from_str(~"-0") {
|
||||
Some(v) if is_zero(v) => assert!(is_negative(v)),
|
||||
_ => fail!()
|
||||
}
|
||||
match from_str(~"0") {
|
||||
Some(v) if is_zero(v) => assert!(is_positive(v)),
|
||||
_ => fail!()
|
||||
}
|
||||
|
||||
assert!(from_str(~"").is_none());
|
||||
assert!(from_str(~"x").is_none());
|
||||
assert!(from_str(~" ").is_none());
|
||||
assert!(from_str(~" ").is_none());
|
||||
assert!(from_str(~"e").is_none());
|
||||
assert!(from_str(~"E").is_none());
|
||||
assert!(from_str(~"E1").is_none());
|
||||
assert!(from_str(~"1e1e1").is_none());
|
||||
assert!(from_str(~"1e1.1").is_none());
|
||||
assert!(from_str(~"1e1-1").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_from_str_hex() {
|
||||
assert!(from_str_hex(~"a4") == Some(164.));
|
||||
assert!(from_str_hex(~"a4.fe") == Some(164.9921875));
|
||||
assert!(from_str_hex(~"-a4.fe") == Some(-164.9921875));
|
||||
assert!(from_str_hex(~"+a4.fe") == Some(164.9921875));
|
||||
assert!(from_str_hex(~"ff0P4") == Some(0xff00 as float));
|
||||
assert!(from_str_hex(~"ff0p4") == Some(0xff00 as float));
|
||||
assert!(from_str_hex(~"ff0p-4") == Some(0xff as float));
|
||||
assert!(from_str_hex(~".") == Some(0.));
|
||||
assert!(from_str_hex(~".p1") == Some(0.));
|
||||
assert!(from_str_hex(~".p-1") == Some(0.));
|
||||
assert!(from_str_hex(~"f.") == Some(15.));
|
||||
assert!(from_str_hex(~".f") == Some(0.9375));
|
||||
assert!(from_str_hex(~"0.f") == Some(0.9375));
|
||||
assert!(from_str_hex(~"-.f") == Some(-0.9375));
|
||||
assert!(from_str_hex(~"-f") == Some(-15.));
|
||||
assert!(from_str_hex(~"inf") == Some(infinity));
|
||||
assert!(from_str_hex(~"+inf") == Some(infinity));
|
||||
assert!(from_str_hex(~"-inf") == Some(neg_infinity));
|
||||
// note: NaN != NaN, hence this slightly complex test
|
||||
match from_str_hex(~"NaN") {
|
||||
Some(f) => assert!(is_NaN(f)),
|
||||
None => fail!()
|
||||
}
|
||||
// note: -0 == 0, hence these slightly more complex tests
|
||||
match from_str_hex(~"-0") {
|
||||
Some(v) if is_zero(v) => assert!(is_negative(v)),
|
||||
_ => fail!()
|
||||
}
|
||||
match from_str_hex(~"0") {
|
||||
Some(v) if is_zero(v) => assert!(is_positive(v)),
|
||||
_ => fail!()
|
||||
}
|
||||
assert!(from_str_hex(~"e") == Some(14.));
|
||||
assert!(from_str_hex(~"E") == Some(14.));
|
||||
assert!(from_str_hex(~"E1") == Some(225.));
|
||||
assert!(from_str_hex(~"1e1e1") == Some(123361.));
|
||||
assert!(from_str_hex(~"1e1.1") == Some(481.0625));
|
||||
|
||||
assert!(from_str_hex(~"").is_none());
|
||||
assert!(from_str_hex(~"x").is_none());
|
||||
assert!(from_str_hex(~" ").is_none());
|
||||
assert!(from_str_hex(~" ").is_none());
|
||||
assert!(from_str_hex(~"p").is_none());
|
||||
assert!(from_str_hex(~"P").is_none());
|
||||
assert!(from_str_hex(~"P1").is_none());
|
||||
assert!(from_str_hex(~"1p1p1").is_none());
|
||||
assert!(from_str_hex(~"1p1.1").is_none());
|
||||
assert!(from_str_hex(~"1p1-1").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_hex() {
|
||||
assert!(to_str_hex(164.) == ~"a4");
|
||||
assert!(to_str_hex(164.9921875) == ~"a4.fe");
|
||||
assert!(to_str_hex(-164.9921875) == ~"-a4.fe");
|
||||
assert!(to_str_hex(0xff00 as float) == ~"ff00");
|
||||
assert!(to_str_hex(-(0xff00 as float)) == ~"-ff00");
|
||||
assert!(to_str_hex(0.) == ~"0");
|
||||
assert!(to_str_hex(15.) == ~"f");
|
||||
assert!(to_str_hex(-15.) == ~"-f");
|
||||
assert!(to_str_hex(0.9375) == ~"0.f");
|
||||
assert!(to_str_hex(-0.9375) == ~"-0.f");
|
||||
assert!(to_str_hex(infinity) == ~"inf");
|
||||
assert!(to_str_hex(neg_infinity) == ~"-inf");
|
||||
assert!(to_str_hex(NaN) == ~"NaN");
|
||||
assert!(to_str_hex(0.) == ~"0");
|
||||
assert!(to_str_hex(-0.) == ~"-0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_radix() {
|
||||
assert!(to_str_radix(36., 36u) == ~"10");
|
||||
assert!(to_str_radix(8.125, 2u) == ~"1000.001");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_from_str_radix() {
|
||||
assert!(from_str_radix(~"10", 36u) == Some(36.));
|
||||
assert!(from_str_radix(~"1000.001", 2u) == Some(8.125));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_positive() {
|
||||
assert!((is_positive(infinity)));
|
||||
assert!((is_positive(1.)));
|
||||
assert!((is_positive(0.)));
|
||||
assert!((!is_positive(-1.)));
|
||||
assert!((!is_positive(neg_infinity)));
|
||||
assert!((!is_positive(1./neg_infinity)));
|
||||
assert!((!is_positive(NaN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_negative() {
|
||||
assert!((!is_negative(infinity)));
|
||||
assert!((!is_negative(1.)));
|
||||
assert!((!is_negative(0.)));
|
||||
assert!((is_negative(-1.)));
|
||||
assert!((is_negative(neg_infinity)));
|
||||
assert!((is_negative(1./neg_infinity)));
|
||||
assert!((!is_negative(NaN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_nonpositive() {
|
||||
assert!((!is_nonpositive(infinity)));
|
||||
assert!((!is_nonpositive(1.)));
|
||||
assert!((!is_nonpositive(0.)));
|
||||
assert!((is_nonpositive(-1.)));
|
||||
assert!((is_nonpositive(neg_infinity)));
|
||||
assert!((is_nonpositive(1./neg_infinity)));
|
||||
assert!((!is_nonpositive(NaN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_nonnegative() {
|
||||
assert!((is_nonnegative(infinity)));
|
||||
assert!((is_nonnegative(1.)));
|
||||
assert!((is_nonnegative(0.)));
|
||||
assert!((!is_nonnegative(-1.)));
|
||||
assert!((!is_nonnegative(neg_infinity)));
|
||||
assert!((!is_nonnegative(1./neg_infinity)));
|
||||
assert!((!is_nonnegative(NaN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_inf() {
|
||||
assert!(to_str_digits(infinity, 10u) == ~"inf");
|
||||
assert!(to_str_digits(-infinity, 10u) == ~"-inf");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_round() {
|
||||
assert!(round(5.8) == 6.0);
|
||||
assert!(round(5.2) == 5.0);
|
||||
assert!(round(3.0) == 3.0);
|
||||
assert!(round(2.5) == 3.0);
|
||||
assert!(round(-3.5) == -4.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_num() {
|
||||
let ten: float = num::cast(10);
|
||||
let two: float = num::cast(2);
|
||||
|
||||
assert!((ten.add(&two) == num::cast(12)));
|
||||
assert!((ten.sub(&two) == num::cast(8)));
|
||||
assert!((ten.mul(&two) == num::cast(20)));
|
||||
assert!((ten.div(&two) == num::cast(5)));
|
||||
assert!((ten.modulo(&two) == num::cast(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numcast() {
|
||||
assert!((20u == 20f.to_uint()));
|
||||
assert!((20u8 == 20f.to_u8()));
|
||||
assert!((20u16 == 20f.to_u16()));
|
||||
assert!((20u32 == 20f.to_u32()));
|
||||
assert!((20u64 == 20f.to_u64()));
|
||||
assert!((20i == 20f.to_int()));
|
||||
assert!((20i8 == 20f.to_i8()));
|
||||
assert!((20i16 == 20f.to_i16()));
|
||||
assert!((20i32 == 20f.to_i32()));
|
||||
assert!((20i64 == 20f.to_i64()));
|
||||
assert!((20f == 20f.to_float()));
|
||||
assert!((20f32 == 20f.to_f32()));
|
||||
assert!((20f64 == 20f.to_f64()));
|
||||
|
||||
assert!((20f == NumCast::from(20u)));
|
||||
assert!((20f == NumCast::from(20u8)));
|
||||
assert!((20f == NumCast::from(20u16)));
|
||||
assert!((20f == NumCast::from(20u32)));
|
||||
assert!((20f == NumCast::from(20u64)));
|
||||
assert!((20f == NumCast::from(20i)));
|
||||
assert!((20f == NumCast::from(20i8)));
|
||||
assert!((20f == NumCast::from(20i16)));
|
||||
assert!((20f == NumCast::from(20i32)));
|
||||
assert!((20f == NumCast::from(20i64)));
|
||||
assert!((20f == NumCast::from(20f)));
|
||||
assert!((20f == NumCast::from(20f32)));
|
||||
assert!((20f == NumCast::from(20f64)));
|
||||
|
||||
assert!((20f == num::cast(20u)));
|
||||
assert!((20f == num::cast(20u8)));
|
||||
assert!((20f == num::cast(20u16)));
|
||||
assert!((20f == num::cast(20u32)));
|
||||
assert!((20f == num::cast(20u64)));
|
||||
assert!((20f == num::cast(20i)));
|
||||
assert!((20f == num::cast(20i8)));
|
||||
assert!((20f == num::cast(20i16)));
|
||||
assert!((20f == num::cast(20i32)));
|
||||
assert!((20f == num::cast(20i64)));
|
||||
assert!((20f == num::cast(20f)));
|
||||
assert!((20f == num::cast(20f32)));
|
||||
assert!((20f == num::cast(20f64)));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
//
|
@ -1,449 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use T = self::inst::T;
|
||||
|
||||
use to_str::ToStr;
|
||||
use from_str::FromStr;
|
||||
use num::{ToStrRadix, FromStrRadix};
|
||||
use num::strconv;
|
||||
use num;
|
||||
use prelude::*;
|
||||
|
||||
#[cfg(notest)] use cmp::{Eq, Ord};
|
||||
|
||||
pub use cmp::{min, max};
|
||||
|
||||
pub static bits : uint = inst::bits;
|
||||
pub static bytes : uint = (inst::bits / 8);
|
||||
|
||||
pub static min_value: T = (-1 as T) << (bits - 1);
|
||||
pub static max_value: T = min_value - 1 as T;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add(x: T, y: T) -> T { x + y }
|
||||
#[inline(always)]
|
||||
pub fn sub(x: T, y: T) -> T { x - y }
|
||||
#[inline(always)]
|
||||
pub fn mul(x: T, y: T) -> T { x * y }
|
||||
#[inline(always)]
|
||||
pub fn div(x: T, y: T) -> T { x / y }
|
||||
|
||||
/**
|
||||
* Returns the remainder of y / x.
|
||||
*
|
||||
* # Examples
|
||||
* ~~~
|
||||
* assert!(int::rem(5 / 2) == 1);
|
||||
* ~~~
|
||||
*
|
||||
* When faced with negative numbers, the result copies the sign of the
|
||||
* dividend.
|
||||
*
|
||||
* ~~~
|
||||
* assert!(int::rem(2 / -3) == 2);
|
||||
* ~~~
|
||||
*
|
||||
* ~~~
|
||||
* assert!(int::rem(-2 / 3) == -2);
|
||||
* ~~~
|
||||
*
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn rem(x: T, y: T) -> T { x % y }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lt(x: T, y: T) -> bool { x < y }
|
||||
#[inline(always)]
|
||||
pub fn le(x: T, y: T) -> bool { x <= y }
|
||||
#[inline(always)]
|
||||
pub fn eq(x: T, y: T) -> bool { x == y }
|
||||
#[inline(always)]
|
||||
pub fn ne(x: T, y: T) -> bool { x != y }
|
||||
#[inline(always)]
|
||||
pub fn ge(x: T, y: T) -> bool { x >= y }
|
||||
#[inline(always)]
|
||||
pub fn gt(x: T, y: T) -> bool { x > y }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_positive(x: T) -> bool { x > 0 as T }
|
||||
#[inline(always)]
|
||||
pub fn is_negative(x: T) -> bool { x < 0 as T }
|
||||
#[inline(always)]
|
||||
pub fn is_nonpositive(x: T) -> bool { x <= 0 as T }
|
||||
#[inline(always)]
|
||||
pub fn is_nonnegative(x: T) -> bool { x >= 0 as T }
|
||||
|
||||
/**
|
||||
* Iterate over the range [`lo`..`hi`)
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * `lo` - lower bound, inclusive
|
||||
* * `hi` - higher bound, exclusive
|
||||
*
|
||||
* # Examples
|
||||
* ~~~
|
||||
* let mut sum = 0;
|
||||
* for int::range(1, 5) |i| {
|
||||
* sum += i;
|
||||
* }
|
||||
* assert!(sum == 10);
|
||||
* ~~~
|
||||
*/
|
||||
#[inline(always)]
|
||||
/// Iterate over the range [`start`,`start`+`step`..`stop`)
|
||||
pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) {
|
||||
let mut i = start;
|
||||
if step == 0 {
|
||||
fail!(~"range_step called with step == 0");
|
||||
} else if step > 0 { // ascending
|
||||
while i < stop {
|
||||
if !it(i) { break }
|
||||
i += step;
|
||||
}
|
||||
} else { // descending
|
||||
while i > stop {
|
||||
if !it(i) { break }
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Iterate over the range [`lo`..`hi`)
|
||||
pub fn range(lo: T, hi: T, it: &fn(T) -> bool) {
|
||||
range_step(lo, hi, 1 as T, it);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Iterate over the range [`hi`..`lo`)
|
||||
pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) {
|
||||
range_step(hi, lo, -1 as T, it);
|
||||
}
|
||||
|
||||
/// Computes the bitwise complement
|
||||
#[inline(always)]
|
||||
pub fn compl(i: T) -> T {
|
||||
-1 as T ^ i
|
||||
}
|
||||
|
||||
/// Computes the absolute value
|
||||
#[inline(always)]
|
||||
pub fn abs(i: T) -> T {
|
||||
if is_negative(i) { -i } else { i }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Ord for T {
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &T) -> bool { return (*self) < (*other); }
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &T) -> bool { return (*self) <= (*other); }
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &T) -> bool { return (*self) >= (*other); }
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &T) -> bool { return (*self) > (*other); }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl Eq for T {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &T) -> bool { return (*self) == (*other); }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &T) -> bool { return (*self) != (*other); }
|
||||
}
|
||||
|
||||
impl num::Zero for T {
|
||||
#[inline(always)]
|
||||
fn zero() -> T { 0 }
|
||||
}
|
||||
|
||||
impl num::One for T {
|
||||
#[inline(always)]
|
||||
fn one() -> T { 1 }
|
||||
}
|
||||
|
||||
#[cfg(notest)]
|
||||
impl ops::Add<T,T> for T {
|
||||
fn add(&self, other: &T) -> T { *self + *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Sub<T,T> for T {
|
||||
fn sub(&self, other: &T) -> T { *self - *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Mul<T,T> for T {
|
||||
fn mul(&self, other: &T) -> T { *self * *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Div<T,T> for T {
|
||||
fn div(&self, other: &T) -> T { *self / *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Modulo<T,T> for T {
|
||||
fn modulo(&self, other: &T) -> T { *self % *other }
|
||||
}
|
||||
#[cfg(notest)]
|
||||
impl ops::Neg<T> for T {
|
||||
fn neg(&self) -> T { -*self }
|
||||
}
|
||||
|
||||
// String conversion functions and impl str -> num
|
||||
|
||||
/// Parse a string as a number in base 10.
|
||||
#[inline(always)]
|
||||
pub fn from_str(s: &str) -> Option<T> {
|
||||
strconv::from_str_common(s, 10u, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a string as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
||||
strconv::from_str_common(s, radix, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
/// Parse a byte slice as a number in the given base.
|
||||
#[inline(always)]
|
||||
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
|
||||
strconv::from_str_bytes_common(buf, radix, true, false, false,
|
||||
strconv::ExpNone, false)
|
||||
}
|
||||
|
||||
impl FromStr for T {
|
||||
#[inline(always)]
|
||||
fn from_str(s: &str) -> Option<T> {
|
||||
from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStrRadix for T {
|
||||
#[inline(always)]
|
||||
fn from_str_radix(s: &str, radix: uint) -> Option<T> {
|
||||
from_str_radix(s, radix)
|
||||
}
|
||||
}
|
||||
|
||||
// String conversion functions and impl num -> str
|
||||
|
||||
/// Convert to a string as a byte slice in a given base.
|
||||
#[inline(always)]
|
||||
pub fn to_str_bytes<U>(n: T, radix: uint, f: &fn(v: &[u8]) -> U) -> U {
|
||||
let (buf, _) = strconv::to_str_bytes_common(&n, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
f(buf)
|
||||
}
|
||||
|
||||
/// Convert to a string in base 10.
|
||||
#[inline(always)]
|
||||
pub fn to_str(num: T) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, 10u, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
/// Convert to a string in a given base.
|
||||
#[inline(always)]
|
||||
pub fn to_str_radix(num: T, radix: uint) -> ~str {
|
||||
let (buf, _) = strconv::to_str_common(&num, radix, false,
|
||||
strconv::SignNeg, strconv::DigAll);
|
||||
buf
|
||||
}
|
||||
|
||||
impl ToStr for T {
|
||||
#[inline(always)]
|
||||
fn to_str(&self) -> ~str {
|
||||
to_str(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStrRadix for T {
|
||||
#[inline(always)]
|
||||
fn to_str_radix(&self, radix: uint) -> ~str {
|
||||
to_str_radix(*self, radix)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert!(from_str(~"0") == Some(0 as T));
|
||||
assert!(from_str(~"3") == Some(3 as T));
|
||||
assert!(from_str(~"10") == Some(10 as T));
|
||||
assert!(i32::from_str(~"123456789") == Some(123456789 as i32));
|
||||
assert!(from_str(~"00100") == Some(100 as T));
|
||||
|
||||
assert!(from_str(~"-1") == Some(-1 as T));
|
||||
assert!(from_str(~"-3") == Some(-3 as T));
|
||||
assert!(from_str(~"-10") == Some(-10 as T));
|
||||
assert!(i32::from_str(~"-123456789") == Some(-123456789 as i32));
|
||||
assert!(from_str(~"-00100") == Some(-100 as T));
|
||||
|
||||
assert!(from_str(~" ").is_none());
|
||||
assert!(from_str(~"x").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bytes() {
|
||||
use str::to_bytes;
|
||||
assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T));
|
||||
assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T));
|
||||
assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T));
|
||||
assert!(i32::parse_bytes(to_bytes(~"123"), 16u) == Some(291 as i32));
|
||||
assert!(i32::parse_bytes(to_bytes(~"ffff"), 16u) ==
|
||||
Some(65535 as i32));
|
||||
assert!(i32::parse_bytes(to_bytes(~"FFFF"), 16u) ==
|
||||
Some(65535 as i32));
|
||||
assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T));
|
||||
assert!(parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T));
|
||||
|
||||
assert!(parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T));
|
||||
assert!(parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T));
|
||||
assert!(parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T));
|
||||
assert!(i32::parse_bytes(to_bytes(~"-123"), 16u) ==
|
||||
Some(-291 as i32));
|
||||
assert!(i32::parse_bytes(to_bytes(~"-ffff"), 16u) ==
|
||||
Some(-65535 as i32));
|
||||
assert!(i32::parse_bytes(to_bytes(~"-FFFF"), 16u) ==
|
||||
Some(-65535 as i32));
|
||||
assert!(parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T));
|
||||
assert!(parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T));
|
||||
|
||||
assert!(parse_bytes(to_bytes(~"Z"), 35u).is_none());
|
||||
assert!(parse_bytes(to_bytes(~"-9"), 2u).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert!((to_str_radix(0 as T, 10u) == ~"0"));
|
||||
assert!((to_str_radix(1 as T, 10u) == ~"1"));
|
||||
assert!((to_str_radix(-1 as T, 10u) == ~"-1"));
|
||||
assert!((to_str_radix(127 as T, 16u) == ~"7f"));
|
||||
assert!((to_str_radix(100 as T, 10u) == ~"100"));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_to_str_overflow() {
|
||||
let mut i8_val: i8 = 127_i8;
|
||||
assert!((i8::to_str(i8_val) == ~"127"));
|
||||
|
||||
i8_val += 1 as i8;
|
||||
assert!((i8::to_str(i8_val) == ~"-128"));
|
||||
|
||||
let mut i16_val: i16 = 32_767_i16;
|
||||
assert!((i16::to_str(i16_val) == ~"32767"));
|
||||
|
||||
i16_val += 1 as i16;
|
||||
assert!((i16::to_str(i16_val) == ~"-32768"));
|
||||
|
||||
let mut i32_val: i32 = 2_147_483_647_i32;
|
||||
assert!((i32::to_str(i32_val) == ~"2147483647"));
|
||||
|
||||
i32_val += 1 as i32;
|
||||
assert!((i32::to_str(i32_val) == ~"-2147483648"));
|
||||
|
||||
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
|
||||
assert!((i64::to_str(i64_val) == ~"9223372036854775807"));
|
||||
|
||||
i64_val += 1 as i64;
|
||||
assert!((i64::to_str(i64_val) == ~"-9223372036854775808"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_from_str_overflow() {
|
||||
let mut i8_val: i8 = 127_i8;
|
||||
assert!((i8::from_str(~"127") == Some(i8_val)));
|
||||
assert!((i8::from_str(~"128").is_none()));
|
||||
|
||||
i8_val += 1 as i8;
|
||||
assert!((i8::from_str(~"-128") == Some(i8_val)));
|
||||
assert!((i8::from_str(~"-129").is_none()));
|
||||
|
||||
let mut i16_val: i16 = 32_767_i16;
|
||||
assert!((i16::from_str(~"32767") == Some(i16_val)));
|
||||
assert!((i16::from_str(~"32768").is_none()));
|
||||
|
||||
i16_val += 1 as i16;
|
||||
assert!((i16::from_str(~"-32768") == Some(i16_val)));
|
||||
assert!((i16::from_str(~"-32769").is_none()));
|
||||
|
||||
let mut i32_val: i32 = 2_147_483_647_i32;
|
||||
assert!((i32::from_str(~"2147483647") == Some(i32_val)));
|
||||
assert!((i32::from_str(~"2147483648").is_none()));
|
||||
|
||||
i32_val += 1 as i32;
|
||||
assert!((i32::from_str(~"-2147483648") == Some(i32_val)));
|
||||
assert!((i32::from_str(~"-2147483649").is_none()));
|
||||
|
||||
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
|
||||
assert!((i64::from_str(~"9223372036854775807") == Some(i64_val)));
|
||||
assert!((i64::from_str(~"9223372036854775808").is_none()));
|
||||
|
||||
i64_val += 1 as i64;
|
||||
assert!((i64::from_str(~"-9223372036854775808") == Some(i64_val)));
|
||||
assert!((i64::from_str(~"-9223372036854775809").is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_num() {
|
||||
let ten: T = num::cast(10);
|
||||
let two: T = num::cast(2);
|
||||
|
||||
assert!((ten.add(&two) == num::cast(12)));
|
||||
assert!((ten.sub(&two) == num::cast(8)));
|
||||
assert!((ten.mul(&two) == num::cast(20)));
|
||||
assert!((ten.div(&two) == num::cast(5)));
|
||||
assert!((ten.modulo(&two) == num::cast(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_ranges() {
|
||||
let mut l = ~[];
|
||||
|
||||
for range(0,3) |i| {
|
||||
l.push(i);
|
||||
}
|
||||
for range_rev(13,10) |i| {
|
||||
l.push(i);
|
||||
}
|
||||
for range_step(20,26,2) |i| {
|
||||
l.push(i);
|
||||
}
|
||||
for range_step(36,30,-2) |i| {
|
||||
l.push(i);
|
||||
}
|
||||
assert!(l == ~[0,1,2,
|
||||
13,12,11,
|
||||
20,22,24,
|
||||
36,34,32]);
|
||||
|
||||
// None of the `fail`s should execute.
|
||||
for range(10,0) |_i| {
|
||||
fail!(~"unreachable");
|
||||
}
|
||||
for range_rev(0,10) |_i| {
|
||||
fail!(~"unreachable");
|
||||
}
|
||||
for range_step(10,0,1) |_i| {
|
||||
fail!(~"unreachable");
|
||||
}
|
||||
for range_step(0,10,-1) |_i| {
|
||||
fail!(~"unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
#[ignore(cfg(windows))]
|
||||
fn test_range_step_zero_step() {
|
||||
for range_step(0,10,0) |_i| {}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations and constants for `i16`
|
||||
|
||||
use num::NumCast;
|
||||
|
||||
mod inst {
|
||||
pub type T = i16;
|
||||
pub static bits: uint = ::u16::bits;
|
||||
}
|
||||
|
||||
impl NumCast for i16 {
|
||||
/**
|
||||
* Cast `n` to a `i16`
|
||||
*/
|
||||
#[inline(always)]
|
||||
fn from<N:NumCast>(n: N) -> i16 { n.to_i16() }
|
||||
|
||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
||||
|
||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
||||
#[inline(always)] fn to_i16(&self) -> i16 { *self }
|
||||
#[inline(always)] fn to_i32(&self) -> i32 { *self as i32 }
|
||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
||||
|
||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numcast() {
|
||||
assert!((20u == 20i16.to_uint()));
|
||||
assert!((20u8 == 20i16.to_u8()));
|
||||
assert!((20u16 == 20i16.to_u16()));
|
||||
assert!((20u32 == 20i16.to_u32()));
|
||||
assert!((20u64 == 20i16.to_u64()));
|
||||
assert!((20i == 20i16.to_int()));
|
||||
assert!((20i8 == 20i16.to_i8()));
|
||||
assert!((20i16 == 20i16.to_i16()));
|
||||
assert!((20i32 == 20i16.to_i32()));
|
||||
assert!((20i64 == 20i16.to_i64()));
|
||||
assert!((20f == 20i16.to_float()));
|
||||
assert!((20f32 == 20i16.to_f32()));
|
||||
assert!((20f64 == 20i16.to_f64()));
|
||||
|
||||
assert!((20i16 == NumCast::from(20u)));
|
||||
assert!((20i16 == NumCast::from(20u8)));
|
||||
assert!((20i16 == NumCast::from(20u16)));
|
||||
assert!((20i16 == NumCast::from(20u32)));
|
||||
assert!((20i16 == NumCast::from(20u64)));
|
||||
assert!((20i16 == NumCast::from(20i)));
|
||||
assert!((20i16 == NumCast::from(20i8)));
|
||||
assert!((20i16 == NumCast::from(20i16)));
|
||||
assert!((20i16 == NumCast::from(20i32)));
|
||||
assert!((20i16 == NumCast::from(20i64)));
|
||||
assert!((20i16 == NumCast::from(20f)));
|
||||
assert!((20i16 == NumCast::from(20f32)));
|
||||
assert!((20i16 == NumCast::from(20f64)));
|
||||
|
||||
assert!((20i16 == num::cast(20u)));
|
||||
assert!((20i16 == num::cast(20u8)));
|
||||
assert!((20i16 == num::cast(20u16)));
|
||||
assert!((20i16 == num::cast(20u32)));
|
||||
assert!((20i16 == num::cast(20u64)));
|
||||
assert!((20i16 == num::cast(20i)));
|
||||
assert!((20i16 == num::cast(20i8)));
|
||||
assert!((20i16 == num::cast(20i16)));
|
||||
assert!((20i16 == num::cast(20i32)));
|
||||
assert!((20i16 == num::cast(20i64)));
|
||||
assert!((20i16 == num::cast(20f)));
|
||||
assert!((20i16 == num::cast(20f32)));
|
||||
assert!((20i16 == num::cast(20f64)));
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Operations and constants for `i32`
|
||||
|
||||
use num::NumCast;
|
||||
|
||||
mod inst {
|
||||
pub type T = i32;
|
||||
pub static bits: uint = ::u32::bits;
|
||||
}
|
||||
|
||||
impl NumCast for i32 {
|
||||
/**
|
||||
* Cast `n` to a `i32`
|
||||
*/
|
||||
#[inline(always)]
|
||||
fn from<N:NumCast>(n: N) -> i32 { n.to_i32() }
|
||||
|
||||
#[inline(always)] fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[inline(always)] fn to_u16(&self) -> u16 { *self as u16 }
|
||||
#[inline(always)] fn to_u32(&self) -> u32 { *self as u32 }
|
||||
#[inline(always)] fn to_u64(&self) -> u64 { *self as u64 }
|
||||
#[inline(always)] fn to_uint(&self) -> uint { *self as uint }
|
||||
|
||||
#[inline(always)] fn to_i8(&self) -> i8 { *self as i8 }
|
||||
#[inline(always)] fn to_i16(&self) -> i16 { *self as i16 }
|
||||
#[inline(always)] fn to_i32(&self) -> i32 { *self }
|
||||
#[inline(always)] fn to_i64(&self) -> i64 { *self as i64 }
|
||||
#[inline(always)] fn to_int(&self) -> int { *self as int }
|
||||
|
||||
#[inline(always)] fn to_f32(&self) -> f32 { *self as f32 }
|
||||
#[inline(always)] fn to_f64(&self) -> f64 { *self as f64 }
|
||||
#[inline(always)] fn to_float(&self) -> float { *self as float }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numcast() {
|
||||
assert!((20u == 20i32.to_uint()));
|
||||
assert!((20u8 == 20i32.to_u8()));
|
||||
assert!((20u16 == 20i32.to_u16()));
|
||||
assert!((20u32 == 20i32.to_u32()));
|
||||
assert!((20u64 == 20i32.to_u64()));
|
||||
assert!((20i == 20i32.to_int()));
|
||||
assert!((20i8 == 20i32.to_i8()));
|
||||
assert!((20i16 == 20i32.to_i16()));
|
||||
assert!((20i32 == 20i32.to_i32()));
|
||||
assert!((20i64 == 20i32.to_i64()));
|
||||
assert!((20f == 20i32.to_float()));
|
||||
assert!((20f32 == 20i32.to_f32()));
|
||||
assert!((20f64 == 20i32.to_f64()));
|
||||
|
||||
assert!((20i32 == NumCast::from(20u)));
|
||||
assert!((20i32 == NumCast::from(20u8)));
|
||||
assert!((20i32 == NumCast::from(20u16)));
|
||||
assert!((20i32 == NumCast::from(20u32)));
|
||||
assert!((20i32 == NumCast::from(20u64)));
|
||||
assert!((20i32 == NumCast::from(20i)));
|
||||
assert!((20i32 == NumCast::from(20i8)));
|
||||
assert!((20i32 == NumCast::from(20i16)));
|
||||
assert!((20i32 == NumCast::from(20i32)));
|
||||
assert!((20i32 == NumCast::from(20i64)));
|
||||
assert!((20i32 == NumCast::from(20f)));
|
||||
assert!((20i32 == NumCast::from(20f32)));
|
||||
assert!((20i32 == NumCast::from(20f64)));
|
||||
|
||||
assert!((20i32 == num::cast(20u)));
|
||||
assert!((20i32 == num::cast(20u8)));
|
||||
assert!((20i32 == num::cast(20u16)));
|
||||
assert!((20i32 == num::cast(20u32)));
|
||||
assert!((20i32 == num::cast(20u64)));
|
||||
assert!((20i32 == num::cast(20i)));
|
||||
assert!((20i32 == num::cast(20i8)));
|
||||
assert!((20i32 == num::cast(20i16)));
|
||||
assert!((20i32 == num::cast(20i32)));
|
||||
assert!((20i32 == num::cast(20i64)));
|
||||
assert!((20i32 == num::cast(20f)));
|
||||
assert!((20i32 == num::cast(20f32)));
|
||||
assert!((20i32 == num::cast(20f64)));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user